ffmpeg代码实现自定义encoder

Posted DoubleLi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ffmpeg代码实现自定义encoder相关的知识,希望对你有一定的参考价值。

1、概述

本文主要讲述如何用ffmpeg代码实现自己的encoder。

2、代码

[cpp] view plain copy
 
  1. /*  
  2. *本程序主要实现一个自己的encoder并加入到encoder链中去,供api调用 
  3. *作者:缪国凯(MK)  
  4. *[email protected]  
  5. *2015-6-4  
  6. */   
  7.   
  8. #include "stdafx.h"  
  9.   
  10. #ifdef __cplusplus  
  11. extern "C"  
  12. {  
  13. #endif  
  14. #include <libavformat/avformat.h>  
  15. #include <libavcodec/avcodec.h>  
  16. #include <libavutil/pixdesc.h>  
  17. #  
  18. #ifdef __cplusplus  
  19. };  
  20. #endif  
  21.   
  22. #pragma comment(lib, "avcodec.lib")  
  23. #pragma comment(lib, "avformat.lib")  
  24. #pragma comment(lib, "avutil.lib")  
  25. //#pragma comment(lib, "avdevice.lib")  
  26. //#pragma comment(lib, "avfilter.lib")  
  27. //#pragma comment(lib, "postproc.lib")  
  28. //#pragma comment(lib, "swresample.lib")  
  29. //#pragma comment(lib, "swscale.lib")  
  30.   
  31. static av_cold int mk_encode_init(AVCodecContext *avctx)  
  32. {  
  33.     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);  
  34.   
  35.     avctx->coded_frame = av_frame_alloc();  
  36.     avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;  
  37.     avctx->bits_per_coded_sample = av_get_bits_per_pixel(desc);  
  38.     if(!avctx->codec_tag)  
  39.         avctx->codec_tag = avcodec_pix_fmt_to_codec_tag(avctx->pix_fmt);  
  40.     return 0;  
  41. }  
  42.   
  43. static int mk_encode(AVCodecContext *avctx, AVPacket *pkt,  
  44.     const AVFrame *frame, int *got_packet)  
  45. {  
  46.     int ret = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);  
  47.   
  48.     if (ret < 0)  
  49.         return ret;  
  50.   
  51.     if (pkt->data == NULL && pkt->size == 0)  
  52.     {  
  53.         av_new_packet(pkt,ret);  
  54.         pkt->size = ret;  
  55.     }  
  56.   
  57. //  if ((ret = ff_alloc_packet2(avctx, pkt, ret)) < 0)  
  58. //      return ret;  
  59.   
  60.     if ((ret = avpicture_layout((const AVPicture *)frame, avctx->pix_fmt, avctx->width,  
  61.         avctx->height, pkt->data, pkt->size)) < 0)  
  62.         return ret;  
  63.   
  64. //  if(avctx->codec_tag == AV_RL32("yuv2") && ret > 0 &&  
  65. //      avctx->pix_fmt   == AV_PIX_FMT_YUYV422)   
  66. //  {  
  67. //          int x;  
  68. //          for(x = 1; x < avctx->height*avctx->width*2; x += 2)  
  69. //              pkt->data[x] ^= 0x80;  
  70. //  }  
  71.     pkt->flags |= AV_PKT_FLAG_KEY;  
  72.     *got_packet = 1;  
  73.     return 0;  
  74. }  
  75.   
  76. static av_cold int mk_close(AVCodecContext *avctx)  
  77. {  
  78.     av_frame_free(&avctx->coded_frame);  
  79.     return 0;  
  80. }  
  81.   
  82. AVCodec ff_mkvideo_encoder = {  
  83.     /*.name           = */"mkvideo",  
  84.     /*.long_name      = */"mk video",  
  85.     /*.type           = */AVMEDIA_TYPE_VIDEO,  
  86.     /*.id             = */AV_CODEC_ID_MKVIDEO,  
  87.     /*.capabilities = */0,  
  88.     /*.supported_framerates = */NULL,  
  89.     /*.pix_fmts     = */NULL,  
  90.     /*.supported_samplerates = */NULL,  
  91.     /*.sample_fmts  = */NULL,  
  92.     /*.channel_layouts = */NULL,  
  93.     /*.max_lowres       = */0,  
  94.     /*.priv_class       = */NULL,  
  95.     /*.profiles     = */NULL,  
  96.     /*.priv_data_size   = */0,  
  97.     /*.next         = */NULL,  
  98.     /*.init_thread_copy = */NULL,  
  99.     /*.update_thread_context = */NULL,  
  100.     /*.defaults     = */NULL,  
  101.     /*.init_static_data = */NULL,     
  102.     /*.init           = */mk_encode_init,  
  103.     /*.encode_sub       = */NULL,  
  104.     /*.encode2        = */mk_encode,  
  105.     /*.decode           = */NULL,  
  106.     /*.close          = */mk_close,  
  107. };  
  108.   
  109. void help()  
  110. {  
  111.     printf("**********************************************\n");  
  112.     printf("Usage:\n");  
  113.     printf("    MyMuxer [inputfile] [outputfile] \n");  
  114.     printf("\n");  
  115.     printf("Examples: \n");  
  116.     printf("    MyMuxer a.avi a.yuv \n");  
  117.     printf("**********************************************\n");    
  118. }  
  119.   
  120. int _tmain(int argc, _TCHAR* argv[])  
  121. {  
  122.     if(argc < 3 || (!strcmp(argv[1],"--help")))  
  123.     {  
  124.         help();  
  125.         return 0;  
  126.     }  
  127.   
  128.     av_register_all();  
  129.     avcodec_register(&ff_mkvideo_encoder);  
  130.   
  131.     AVFormatContext *in_fxt = NULL, *out_fxt = NULL;  
  132.     AVStream *out_stream = NULL;  
  133.     int video_index = -1;  
  134.   
  135.     if (avformat_open_input(&in_fxt, argv[1], NULL, NULL) < 0)  
  136.     {  
  137.         printf("can not open the input file context!\n");  
  138.         goto end;  
  139.     }  
  140.     if (avformat_find_stream_info(in_fxt, NULL) < 0)  
  141.     {  
  142.         printf("can not find the stream info!\n");  
  143.         goto end;  
  144.     }  
  145.   
  146.     if(avformat_alloc_output_context2(&out_fxt, NULL, NULL, argv[2]) < 0)  
  147.     {  
  148.         printf("can not alloc output context!\n");  
  149.         goto end;  
  150.     }  
  151.   
  152.     for (int i = 0; i < in_fxt->nb_streams; i++)  
  153.     {  
  154.         if (in_fxt->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)  
  155.         {  
  156.             //open decoder  
  157.             if(0 > avcodec_open2(in_fxt->streams[i]->codec, avcodec_find_decoder(in_fxt->streams[i]->codec->codec_id), NULL))  
  158.             {  
  159.                 printf("can not find or open decoder!\n");  
  160.                 goto end;  
  161.             }  
  162.             video_index = i;  
  163.             //new stream  
  164.             out_stream = avformat_new_stream(out_fxt, NULL);  
  165.             if (!out_stream)  
  166.             {  
  167.                 printf("can not new stream for output!\n");  
  168.                 goto end;  
  169.             }  
  170.             //set codec context param  
  171.             out_stream->codec->codec = avcodec_find_encoder(/*out_fxt->oformat->video_codec*/AV_CODEC_ID_MKVIDEO);  
  172.             out_stream->codec->height = in_fxt->streams[i]->codec->height;  
  173.             out_stream->codec->width = in_fxt->streams[i]->codec->width;  
  174.   
  175.             out_stream->codec->time_base = in_fxt->streams[i]->time_base;  
  176.             //out_stream->codec->time_base.den = 25;  
  177.   
  178.             out_stream->codec->sample_aspect_ratio = in_fxt->streams[i]->codec->sample_aspect_ratio;           
  179.             out_stream->codec->pix_fmt = in_fxt->streams[i]->codec->pix_fmt;  
  180.   
  181.             out_stream->avg_frame_rate.den = out_stream->codec->time_base.num;  
  182.             out_stream->avg_frame_rate.num = out_stream->codec->time_base.den;  
  183.             if (!out_stream->codec->codec)  
  184.             {  
  185.                 printf("can not find the encoder!\n");  
  186.                 goto end;  
  187.             }  
  188.             if ((avcodec_open2(out_stream->codec, out_stream->codec->codec, NULL)) < 0)  
  189.             {  
  190.                 printf("can not open the encoder\n");  
  191.                 goto end;  
  192.             }  
  193.             if (out_fxt->oformat->flags & AVFMT_GLOBALHEADER)  
  194.                 out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;  
  195.             break;  
  196.         }  
  197.     }  
  198.   
  199.     if (-1 == video_index)  
  200.     {  
  201.         printf("found no video stream in input file!\n");  
  202.         goto end;  
  203.     }  
  204.   
  205.     if (!(out_fxt->oformat->flags & AVFMT_NOFILE))  
  206.     {  
  207.         if(avio_open(&out_fxt->pb, argv[2], AVIO_FLAG_WRITE) < 0)  
  208.         {  
  209.             printf("can not open output file handle!\n");  
  210.             goto end;  
  211.         }  
  212.     }  
  213.   
  214.     if(avformat_write_header(out_fxt, NULL) < 0)  
  215.     {  
  216.         printf("can not write the header of the output file!\n");  
  217.         goto end;  
  218.     }  
  219.   
  220.     AVPacket pkt_in, pkt_out;  
  221.     AVFrame *frame;  
  222.     frame = av_frame_alloc();  
  223.     av_init_packet(&pkt_in);  
  224.     av_init_packet(&pkt_out);  
  225.     int got_frame, got_picture;  
  226.     int i = 0, frame_index = 0;  
  227.     while(1)  
  228.     {  
  229.         got_frame = -1;  
  230.         got_picture = -1;  
  231.         if (av_read_frame(in_fxt, &pkt_in) < 0)  
  232.         {  
  233.             break;  
  234.         }  
  235.         if (avcodec_decode_video2(in_fxt->streams[video_index]->codec, frame, &got_frame, &pkt_in) < 0)  
  236.         {  
  237.             printf("can not decoder a frame");  
  238.             break;  
  239.         }  
  240.         av_free_packet(&pkt_in);  
  241.   
  242.         if (got_frame)  
  243.         {  
  244.             frame->pts = i++;  
  245.             pkt_out.data = NULL;//主要这里必须自己初始化,或者必须置为null,不然ff_alloc_packet2函数会报错  
  246.             pkt_out.size = 0;  
  247.             if (avcodec_encode_video2(out_stream->codec, &pkt_out, frame, &got_picture) < 0)  
  248.             {  
  249.                 printf("can not encode a frame!\n");  
  250.                 break;  
  251.             }  
  252.   
  253.             if (got_picture)  
  254.             {  
  255.                 printf("Succeed to encode frame: %5d\tsize:%5d\n",frame_index,pkt_out.size);  
  256.                 pkt_out.stream_index = out_stream->index;  
  257.                 frame_index++;  
  258.                 av_write_frame(out_fxt, &pkt_out);  
  259.                 av_free_packet(&pkt_out);  
  260.             }  
  261.         }  
  262.     }  
  263.     av_frame_free(&frame);  
  264.   
  265.     av_write_trailer(out_fxt);  
  266.   
  267.     //clean  
  268.     avcodec_close(out_stream->codec);  
  269.     avcodec_close(out_fxt->streams[video_index]->codec);  
  270. end:  
  271.     avformat_close_input(&in_fxt);  
  272.   
  273.     if (out_fxt && !(out_fxt->oformat->flags & AVFMT_NOFILE))  
  274.     {  
  275.         avio_close(out_fxt->pb);  
  276.     }  
  277.     avformat_free_context(out_fxt);  
  278.     return 0;  
  279. }  

3、解释

原理和前面的自定义的muxer、demuxer一样,在这里就不多说了。
from:http://blog.csdn.net/dancing_night/article/details/46360851

以上是关于ffmpeg代码实现自定义encoder的主要内容,如果未能解决你的问题,请参考以下文章

把自定义的demuxer加入ffmpeg源码

把自定义的decoder加入ffmpeg源码

Python 实现视频裁剪(附代码) | Python工具

Python 实现视频裁剪(附代码) | Python工具

Python 实现图片裁剪(附代码) | Python工具

使用ffmpeg实现单线程异步的视频播放器