您的位置:首页 > 其它

使用ffmpeg开源库将h264封装为mp4格式

2015-07-19 15:11 337 查看
最近一直在做使用ffmpeg关于读取标准h264格式内存如何封装为mp4格式文件,在经过一周的持续奋战之后在网上找了一些代码,特别的雷神的博客让我获益匪浅,开始不知道如何持续读取发送来的内存块,如何边接受内存边封装为mp4格式文件,找了很多代码也没想出来,后来发现ffmpeg注册的读取拷贝内存的回调函数是自己控制的人为无法控制,经过一番折腾,找了一个比较容易的方法,如果代码有错误的地方希望大家指导,想写一篇博客把自己的代码贴出来。

#include "StdAfx.h"

#include "format.h"

ITAVFormat::ITAVFormat(void)

{

m_ifmt_ctx = NULL;

m_ofmt_ctx = NULL;

m_ofmt = NULL;

m_bufAvalloc = NULL;

m_fileName = NULL;

for(int i=0; i<BUF_UNIT_NUM; i++)

{

m_bufDeq.data[i].ptr = new unsigned char[UNIT_SIZE];

memset(m_bufDeq.data[i].ptr,0,UNIT_SIZE);

m_bufDeq.data[i].size = 0;

m_bufDeq.data[i].readsize = 0;

}

m_bufDeq.head = 0;

m_bufDeq.tail = 0;

m_countFill = 0;

m_frame_index = 0;

m_startCode = 0;

}

ITAVFormat::~ITAVFormat(void)

{

for(int i=0; i<BUF_UNIT_NUM; i++)

{

delete []m_bufDeq.data[i].ptr;

m_bufDeq.data[i].size = 0;

m_bufDeq.data[i].readsize = 0;

}

m_bufDeq.head = 0;

m_bufDeq.tail = 0;

}

int ITAVFormat::read_data(void *opaque, uint8_t *buf, int buf_size)

{

//printf("readData!!!!!!!!!!!!\n");

ITAVFormat* pThis = (ITAVFormat*)opaque;

if(pThis->m_bufDeq.head == pThis->m_bufDeq.tail)

{

//printf("*********head==tail********buf_size=%ld\n",buf_size);

return 0;

}

else

{

int head = pThis->m_bufDeq.head;

buf_size = FFMIN(buf_size, pThis->m_bufDeq.data[head].size);

printf("ptr:%p,size:%u,buf_size=%u\n",pThis->m_bufDeq.data[head].ptr, pThis->m_bufDeq.data[head].size,buf_size);

/* copy internal buffer data to buf */

memcpy(buf, pThis->m_bufDeq.data[head].ptr+pThis->m_bufDeq.data[head].readsize, buf_size);

pThis->m_bufDeq.data[head].readsize += buf_size;

pThis->m_bufDeq.data[head].size -= buf_size;

if(pThis->m_bufDeq.data[head].size <= 0)

{

pThis->m_bufDeq.data[head].readsize = 0;

pThis->m_bufDeq.head = (pThis->m_bufDeq.head+1)%BUF_UNIT_NUM;

}

return buf_size;

}

}

void ITAVFormat::init()

{

av_register_all();

}

int ITAVFormat::fillBuffer(unsigned char* buff,int len)

{

//buffer_data b

if(buff == NULL)

return TRUE;

if(len > UNIT_SIZE)

return FALSE;

int tail = m_bufDeq.tail;

memcpy(m_bufDeq.data[tail].ptr,buff,len);

m_bufDeq.data[tail].size = len;

m_bufDeq.data[tail].readsize = 0;

m_bufDeq.tail = (m_bufDeq.tail+1)%BUF_UNIT_NUM;

if(m_countFill == 0)

{

m_startCode = start();

if(m_startCode < 0)

return FALSE;

m_countFill++;

}

else

writeFrame();

return TRUE;

}

int ITAVFormat::writeFrame()

{

int ret = -1;

AVPacket pkt;

while(1)

{

AVStream *in_stream, *out_stream;

//Get an AVPacket

ret = av_read_frame(m_ifmt_ctx, &pkt);

//printf("ret=%d\n",ret);

if (ret < 0)

{

printf("ret = %d\n",ret);

break;

}

in_stream = m_ifmt_ctx->streams[pkt.stream_index];

out_stream = m_ofmt_ctx->streams[pkt.stream_index];

///如果没有显示时间戳自己加上时间戳并且将显示时间戳赋值给解码时间戳

if(pkt.pts==AV_NOPTS_VALUE){

//Write PTS

AVRational time_base1=in_stream->time_base;

//Duration between 2 frames (us)

int64_t calc_duration=(double)AV_TIME_BASE/av_q2d(in_stream->r_frame_rate);

//Parameters

pkt.pts=(double)(m_frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);

pkt.dts=pkt.pts;

pkt.duration=(double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);

m_frame_index++;

}

//Convert PTS/DTS

pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);

pkt.pos = -1;

//Write

if (av_interleaved_write_frame(m_ofmt_ctx, &pkt) < 0) {

printf( "Error muxing packet\n");

break;

}

//printf("Write %8d frames to output file\n",frame_index);

av_free_packet(&pkt);

m_frame_index++;

}

return TRUE;

}

// av_probe_input_buffer2

// AVPROBE_SCORE_MAX

int ITAVFormat::start()

{

int ret,i;

AVIOContext* pb = NULL;

AVInputFormat* piFmt = NULL;

m_bufAvalloc = (unsigned char*)av_malloc(32768);

pb = avio_alloc_context(m_bufAvalloc, 32768, 0, (void*)this, ITAVFormat::read_data, NULL, NULL);

if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0)

return -1;

else{

printf("format:%s[%s]\n", piFmt->name, piFmt->long_name);

}

m_ifmt_ctx = avformat_alloc_context();

m_ifmt_ctx->pb = pb;

//Input

if (avformat_open_input(&m_ifmt_ctx, "", piFmt, NULL) != 0){//iformat,priv_data赋值,pb, nbstreams,streams为null

printf("Couldn't open input stream.(无法打开输入流)\n");

return -2;

}

if ((ret = avformat_find_stream_info(m_ifmt_ctx, 0)) < 0) {

printf( "Failed to retrieve input stream information");

return -3;

}

//Output

avformat_alloc_output_context2(&m_ofmt_ctx, NULL, NULL, m_fileName);

if (!m_ofmt_ctx) {

printf( "Could not create output context\n");

return -4;

//goto end;

}

m_ofmt = m_ofmt_ctx->oformat;

for (i = 0; i < m_ifmt_ctx->nb_streams; i++) {

//Create output AVStream according to input AVStream

AVStream *in_stream = m_ifmt_ctx->streams[i];

AVStream *out_stream = avformat_new_stream(m_ofmt_ctx, in_stream->codec->codec);

if (!out_stream) {

printf( "Failed allocating output stream\n");

return -5;

}

//Copy the settings of AVCodecContext

if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) {

printf( "Failed to copy context from input to output stream codec context\n");

return -6;

}

out_stream->codec->codec_tag = 0;

if (m_ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)

{

out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;

}

}

//Output information------------------

av_dump_format(m_ofmt_ctx, 0, m_fileName, 1);

//Open output file

if (!(m_ofmt->flags & AVFMT_NOFILE)) {

ret = avio_open(&m_ofmt_ctx->pb, m_fileName, AVIO_FLAG_WRITE);

if (ret < 0) {

printf( "Could not open output file '%s'", m_fileName);

return -7;

}

}

//Write file header

if (avformat_write_header(m_ofmt_ctx, NULL) < 0) {

printf( "Error occurred when opening output file\n");

return -8;

}

return TRUE;

}

void ITAVFormat::setFileName(char* fileName)

{

m_fileName = fileName;

}

void ITAVFormat::finish()

{

if(m_startCode < 0)

return;

//Write file trailer

av_write_trailer(m_ofmt_ctx);

//av_free(m_bufAvalloc);

avformat_close_input(&m_ifmt_ctx);

/* close output */

if (m_ofmt_ctx && !(m_ofmt->flags & AVFMT_NOFILE))

avio_close(m_ofmt_ctx->pb);

avformat_free_context(m_ofmt_ctx);

//av_free(m_bufAvalloc);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: