关于ffmpeg的例子muxing.c

96 篇文章 0 订阅
80 篇文章 1 订阅

http://blog.csdn.net/relar/article/details/21785673


在ffmpeg的官方例子中有一个muxing.c,这个例子是演示如何用ffmpeg进行打包(muxing),但是这个例子有些问题,说好听点是不完善,说不好听就是有错误。ffmpeg.c是非常完善的,对比ffmpeg.c我发现主要有以下两个错误:

1、在使用avcodec_encode_audio2/avcodec_encode_video2编码前,没有给定时间戳。

2、在main函数的for循环之后,没有flush,也就是还有一些延迟的帧在缓冲中,没有写进输出文件。在编码时,并不是每一个输入帧立即编码得到输出帧,而往往是输入N多帧之后才开始输出帧,我见过最多输入60帧之后才出现第一个输入帧的,那么就出现了一个问题,以输入为循环体,输入结束循环也结束,那么就还有一些帧在缓存中,此时我们需要将其拿出来,编码,再写进输出文件。

下面我以音频为例修改了代码,首先是函数write_audio_frame

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static void write_audio_frame(AVFormatContext *oc, AVStream *st)  
  2. {  
  3.     AVCodecContext *c;  
  4.     AVPacket pkt = { 0 }; // data and size must be 0;  
  5.     AVFrame *frame = NULL;  
  6.     int got_packet, ret, dst_nb_samples;  
  7.     AVRational r = {1, AV_TIME_BASE};  
  8.   
  9.     av_init_packet(&pkt);  
  10.     pkt.data = NULL;  
  11.     pkt.size = 0;  
  12.     c = st->codec;  
  13.   
  14.     if(!frame && !(frame = avcodec_alloc_frame()))  
  15.         return ;  
  16.     else  
  17.         avcodec_get_frame_defaults(frame);  
  18.   
  19.     get_audio_frame((int16_t *)src_samples_data[0], src_nb_samples, c->channels);  
  20.   
  21.     /* convert samples from native format to destination codec format, using the resampler */  
  22.     if (swr_ctx) {  
  23.         /* compute destination number of samples */  
  24.         dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, c->sample_rate) + src_nb_samples,  
  25.                                         c->sample_rate, c->sample_rate, AV_ROUND_UP);  
  26.         if (dst_nb_samples > max_dst_nb_samples) {  
  27.             av_free(dst_samples_data[0]);  
  28.             ret = av_samples_alloc(dst_samples_data, &dst_samples_linesize, c->channels,  
  29.                                    dst_nb_samples, c->sample_fmt, 0);  
  30.             if (ret < 0)  
  31.                 exit(1);  
  32.             max_dst_nb_samples = dst_nb_samples;  
  33.             dst_samples_size = av_samples_get_buffer_size(NULL, c->channels, dst_nb_samples,  
  34.                                                           c->sample_fmt, 0);  
  35.         }  
  36.   
  37.         /* convert to destination format */  
  38.         ret = swr_convert(swr_ctx,  
  39.                           dst_samples_data, dst_nb_samples,  
  40.                           (const uint8_t **)src_samples_data, src_nb_samples);  
  41.         if (ret < 0) {  
  42.             fprintf(stderr, "Error while converting\n");  
  43.             exit(1);  
  44.         }  
  45.     } else {  
  46.         dst_samples_data[0] = src_samples_data[0];  
  47.         dst_nb_samples = src_nb_samples;  
  48.     }  
  49.   
  50.     frame->nb_samples = dst_nb_samples;  
  51.     avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, dst_samples_data[0], dst_samples_size, 0);  
  52.     //下面两句我加的。编码前一定要给frame时间戳  
  53.     frame->pts = lastpts;  
  54.     lastpts = frame->pts + frame->nb_samples;  
  55.   
  56.     ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet);   //如果没有前两句,编码之后的pts是无效的  
  57.     if (ret < 0) {  
  58.         fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret));  
  59.         exit(1);  
  60.     }  
  61.       
  62.   
  63.     if (!got_packet)  
  64.         return;  
  65.   
  66.     pkt.stream_index = st->index;  
  67.     //下面两句我加的,加了才不是提示“encoder did not produce proper pts, make some up”错误  
  68.     pkt.pts = av_rescale_q(pkt.pts, st->codec->time_base, st->time_base);//  
  69.     pkt.dts = av_rescale_q(pkt.dts, st->codec->time_base, st->time_base);//  
  70.     pkt.duration = av_rescale_q(pkt.duration, st->codec->time_base, st->time_base);  
  71.     /* Write the compressed frame to the media file. */  
  72.     ret = av_interleaved_write_frame(oc, &pkt);  
  73.     if (ret != 0) {  
  74.         fprintf(stderr, "Error while writing audio frame: %s\n",  
  75.                 av_err2str(ret));  
  76.         exit(1);  
  77.     }  
  78.     avcodec_free_frame(&frame);  
  79. }  
修改main函数中的代码,在for(;;)循环之后:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //下面几行是获得delay帧  
  2.     c = audio_st->codec;  
  3.     for(got_output=1; got_output>0; i++)  
  4.     {  
  5.         av_init_packet(&pkt);    
  6.         pkt.data = NULL;  
  7.         pkt.size = 0;  
  8.         ret = avcodec_encode_audio2(c, &pkt, NULL, &got_output);    
  9.         if (ret < 0)   
  10.         {    
  11.             fprintf(stderr, "Error encoding frame\n");    
  12.             exit(1);   
  13.         }  
  14.         if (got_output)   
  15.         {   
  16.         //  audio_st->pts.val += 1024;//av_rescale_q(1, audio_st->codec->time_base, audio_st->time_base);  
  17.             pkt.pts = av_rescale_q(pkt.pts, c->time_base, audio_st->time_base);//audio_st->pts.val;  
  18.             pkt.dts = av_rescale_q(pkt.dts, c->time_base, audio_st->time_base);//audio_st->pts.val;  
  19.             pkt.duration = av_rescale_q(pkt.duration, c->time_base, audio_st->time_base);  
  20.             ret = av_interleaved_write_frame(oc, &pkt);  
  21.             av_free_packet(&pkt);    
  22.         }  
  23.     }  

这里仅仅修改了音频方面的处理,视频方面可以家有完全参考以上代码。另外我还将原来由程序生成的原始图像,改为了从BMP文件读取画面,成功。有兴趣的朋友可以交流。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值