Advertisement
Guest User

video-sound-transcoding-test.cpp

a guest
Nov 21st, 2012
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.62 KB | None | 0 0
  1. /*
  2.  
  3.   Compile with:
  4.   g++ -Wall -O2 -g -D__STDC_CONSTANT_MACROS  -o video-sound-transcoding-test video-sound-transcoding-test.cpp -lm -lavdevice -lavformat -lavfilter -lavcodec -lswresample -lswscale -lavutil
  5.  
  6. */
  7.  
  8. extern "C"
  9. {
  10. #include <libavutil/avutil.h>
  11. #include <libavutil/parseutils.h>
  12. #include <libavutil/mathematics.h>
  13. #include <libavutil/opt.h>
  14. #include <libavcodec/avcodec.h>
  15. #include <libavformat/avformat.h>
  16. #include <libswscale/swscale.h>
  17. #include <libswresample/swresample.h>
  18. #include <libavfilter/avfilter.h>
  19. #include <libavfilter/avfiltergraph.h>
  20. #include <libavfilter/avcodec.h>
  21. #include <libavfilter/buffersink.h>
  22. #include <libavfilter/buffersrc.h>
  23. #include <libavutil/imgutils.h>
  24. }
  25.  
  26. #include <iostream>
  27.  
  28. using namespace std;
  29.  
  30. //
  31. // Compilation error work around
  32. //
  33. #ifndef av_ts2timestr
  34. #include <vector>
  35. #define AV_TS_MAX_STRING_SIZE 32
  36. static inline string av_ts_make_time_string(int64_t ts, AVRational *tb)
  37. {
  38.     vector<char> buf(AV_TS_MAX_STRING_SIZE);
  39.     if (ts == AV_NOPTS_VALUE) snprintf(buf.data(), AV_TS_MAX_STRING_SIZE, "NOPTS");
  40.     else                      snprintf(buf.data(), AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts);
  41.     return string(buf.data());
  42. }
  43. #define av_ts2timestr(ts, tb) av_ts_make_time_string(ts, tb)
  44. #endif
  45.  
  46. struct MediaContext
  47. {
  48.     MediaContext()
  49.         : formatCtx(0),
  50.           videoCodec(0),
  51.           audioCodec(0),
  52.           videoCodecCtx(0),
  53.           audioCodecCtx(0),
  54.           videoStream(0),
  55.           audioStream(0),
  56.           swsCtx(0),
  57.           videoStreamIndex(-1),
  58.           audioStreamIndex(-1)
  59.     {}
  60.  
  61.     // input or output file name or URI
  62.     string resource;
  63.  
  64.     AVFormatContext *formatCtx;
  65.     AVCodec         *videoCodec;
  66.     AVCodec         *audioCodec;
  67.     AVCodecContext  *videoCodecCtx;
  68.     AVCodecContext  *audioCodecCtx;
  69.     AVStream        *videoStream;
  70.     AVStream        *audioStream;
  71.     SwsContext      *swsCtx;
  72.  
  73.     int              videoStreamIndex;
  74.     int              audioStreamIndex;
  75. };
  76.  
  77.  
  78. MediaContext inCtx;   // Media source
  79. MediaContext outCtx;  // Media destination
  80.  
  81.  
  82. static
  83. void usage(const string& progName)
  84. {
  85.     cout << "Use: " << progName << " <input media file> <output media file>" << endl;
  86. }
  87.  
  88.  
  89.  
  90. static
  91. int openCodecContex(MediaContext &ctx, AVMediaType type)
  92. {
  93.     int ret = -1;
  94.  
  95.     AVStream        **stream;
  96.     AVCodecContext  **codecCtx;
  97.     AVCodec         **codec;
  98.     AVFormatContext *formatCtx;
  99.     int             *streamIndex;
  100.  
  101.     formatCtx = ctx.formatCtx;
  102.  
  103.     if (type == AVMEDIA_TYPE_VIDEO)
  104.     {
  105.         stream      = &ctx.videoStream;
  106.         codecCtx    = &ctx.videoCodecCtx;
  107.         streamIndex = &ctx.videoStreamIndex;
  108.         codec       = &ctx.videoCodec;
  109.     }
  110.     else if (type == AVMEDIA_TYPE_AUDIO)
  111.     {
  112.         stream      = &ctx.audioStream;
  113.         codecCtx    = &ctx.audioCodecCtx;
  114.         streamIndex = &ctx.audioStreamIndex;
  115.         codec       = &ctx.audioCodec;
  116.     }
  117.     else
  118.     {
  119.         cerr << "Unknown media type: " << av_get_media_type_string(type) << endl;
  120.         return -1;
  121.     }
  122.  
  123.  
  124.     ret = av_find_best_stream(formatCtx, type, -1, -1, 0, 0);
  125.     if (ret >= 0)
  126.     {
  127.         *stream   = formatCtx->streams[ret];
  128.         *codecCtx    = (*stream)->codec;
  129.  
  130.         *codec = avcodec_find_decoder((*codecCtx)->codec_id);
  131.  
  132.         if (!(*codec))
  133.         {
  134.             cerr << "Failed to find " << (*codecCtx)->codec_name << " codec" << endl;
  135.             return -1;
  136.         }
  137.  
  138.         int result = avcodec_open2(*codecCtx, *codec, 0);
  139.         if (result < 0)
  140.         {
  141.             cerr << "Failed to open " << (*codec)->name << " codec" << endl;
  142.             return -1;
  143.         }
  144.     }
  145.  
  146.     *streamIndex = ret;
  147.  
  148.     return ret;
  149. }
  150.  
  151.  
  152.  
  153. static
  154. int addStream(MediaContext &ctx, AVMediaType type)
  155. {
  156.     AVCodecID       codecId;
  157.     AVStream        **stream;
  158.     AVCodecContext  **codecCtx;
  159.     AVCodec         **codec;
  160.     AVFormatContext *formatCtx;
  161.     int             *streamIndex;
  162.  
  163.     formatCtx = ctx.formatCtx;
  164.  
  165.     if (type == AVMEDIA_TYPE_VIDEO)
  166.     {
  167.         stream      = &ctx.videoStream;
  168.         codecCtx    = &ctx.videoCodecCtx;
  169.         streamIndex = &ctx.videoStreamIndex;
  170.         codec       = &ctx.videoCodec;
  171.         codecId     = formatCtx->oformat->video_codec;
  172.     }
  173.     else if (type == AVMEDIA_TYPE_AUDIO)
  174.     {
  175.         stream      = &ctx.audioStream;
  176.         codecCtx    = &ctx.audioCodecCtx;
  177.         streamIndex = &ctx.audioStreamIndex;
  178.         codec       = &ctx.audioCodec;
  179.         codecId     = formatCtx->oformat->audio_codec;
  180.     }
  181.     else
  182.     {
  183.         cerr << "Unknown media type: " << av_get_media_type_string(type) << endl;
  184.         return -1;
  185.     }
  186.  
  187.  
  188.     *codec = avcodec_find_encoder(codecId);
  189.     if (!(*codec))
  190.     {
  191.         cerr << "Can't found codec" << endl;
  192.         return -1;
  193.     }
  194.  
  195.     *stream = avformat_new_stream(ctx.formatCtx, *codec);
  196.     if (!*stream)
  197.     {
  198.         cerr << "Can't alloc stream" << endl;
  199.         return -1;
  200.     }
  201.  
  202.     *codecCtx = (*stream)->codec;
  203.  
  204.     avcodec_get_context_defaults3(*codecCtx, *codec);
  205.  
  206.     (*codecCtx)->codec_id = codecId;
  207.  
  208.     if (formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
  209.         (*codecCtx)->flags |= CODEC_FLAG_GLOBAL_HEADER;
  210.  
  211.     *streamIndex = formatCtx->nb_streams - 1;
  212.     return *streamIndex;
  213. }
  214.  
  215.  
  216. static
  217. AVFrame *allocVideoFrame(PixelFormat pixFmt, int width, int height)
  218. {
  219.     if (pixFmt == PIX_FMT_NONE || width <= 0 || height <= 0)
  220.     {
  221.         cerr << "Invalid picture params: format:" << pixFmt << ", w:" << width << ", h:" << height << endl;
  222.         return 0;
  223.     }
  224.  
  225.     AVFrame *outFrame = avcodec_alloc_frame();
  226.     if (!outFrame)
  227.         return outFrame;
  228.  
  229.     outFrame->width  = width;
  230.     outFrame->height = height;
  231.     outFrame->format = pixFmt;
  232.  
  233.     int size = avpicture_get_size(pixFmt, width, height);
  234.     uint8_t *pictBuf = new uint8_t[size];
  235.  
  236.     avpicture_fill((AVPicture*)outFrame,
  237.                    pictBuf,
  238.                    pixFmt, width, height);
  239.  
  240.     return outFrame;
  241. }
  242.  
  243.  
  244. static
  245. void freeVideoFrame(AVFrame **frame)
  246. {
  247.     if (frame == 0 || *frame == 0)
  248.     {
  249.         return;
  250.     }
  251.  
  252.     AVFrame *ptr = *frame;
  253.  
  254.     delete [] ptr->data[0];
  255.  
  256.     avcodec_free_frame(frame);
  257.     *frame = 0;
  258. }
  259.  
  260.  
  261. int main(int argc, char **argv)
  262. {
  263.     // register all formats, protocols and codecs
  264.     av_register_all();
  265.  
  266.     int stat;
  267.  
  268.     if (argc < 3)
  269.     {
  270.         usage(argv[0]);
  271.         return 1;
  272.     }
  273.  
  274.     inCtx.resource  = argv[1];
  275.     outCtx.resource = argv[2];
  276.  
  277.     ////
  278.     //// Prepare input file
  279.     ////
  280.  
  281.     // Open input file
  282.     if (avformat_open_input(&inCtx.formatCtx, inCtx.resource.c_str(), 0, 0) < 0)
  283.     {
  284.         cerr << "Can't open source file: " << inCtx.resource << endl;
  285.         return 1;
  286.     }
  287.  
  288.     // Retrieve stream information
  289.     if (avformat_find_stream_info(inCtx.formatCtx, 0) < 0)
  290.     {
  291.         cerr << "Can't find stream information" << endl;
  292.         return 1;
  293.     }
  294.  
  295.     // Walk via streams
  296.     if (openCodecContex(inCtx, AVMEDIA_TYPE_VIDEO) >= 0)
  297.     {
  298.         // TODO
  299.     }
  300.  
  301.     if (openCodecContex(inCtx, AVMEDIA_TYPE_AUDIO) >= 0)
  302.     {
  303.         // TODO
  304.     }
  305.  
  306.     av_dump_format(inCtx.formatCtx, 0, inCtx.resource.c_str(), 0);
  307.  
  308.  
  309.  
  310.  
  311.     ////
  312.     //// Prepare output file
  313.     ////
  314.  
  315.     // alloc context
  316.     outCtx.formatCtx = avformat_alloc_context();
  317.  
  318.     outCtx.formatCtx->iformat = 0;
  319.     outCtx.formatCtx->oformat = av_guess_format(0, outCtx.resource.c_str(), 0);
  320.  
  321.     if (!outCtx.formatCtx->oformat)
  322.     {
  323.         cout << "Fall back to MPEGTS format" << endl;
  324.         outCtx.formatCtx->oformat = av_guess_format("mpegts", 0, 0);
  325.  
  326.         if (!outCtx.formatCtx->oformat)
  327.         {
  328.             cerr << "Can't found output format for file: " << outCtx.resource << endl;
  329.             return 1;
  330.         }
  331.     }
  332.  
  333.  
  334.     // Setup video stream
  335.     if (inCtx.videoStreamIndex >= 0 && addStream(outCtx, AVMEDIA_TYPE_VIDEO) >= 0)
  336.     {
  337.         outCtx.videoCodecCtx->bit_rate = 400000;
  338.  
  339.         outCtx.videoCodecCtx->width    = inCtx.videoCodecCtx->width;
  340.         outCtx.videoCodecCtx->height   = inCtx.videoCodecCtx->height;
  341.  
  342.         outCtx.videoCodecCtx->time_base.den = 25;
  343.         outCtx.videoCodecCtx->time_base.num = 1;
  344.  
  345.         outCtx.videoCodecCtx->gop_size      = 12;
  346.         outCtx.videoCodecCtx->pix_fmt       = PIX_FMT_YUV420P;
  347.  
  348.         if (outCtx.videoCodec->pix_fmts)
  349.         {
  350.             outCtx.videoCodecCtx->pix_fmt = *outCtx.videoCodec->pix_fmts;
  351.         }
  352.  
  353.         if (outCtx.videoCodecCtx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
  354.         {
  355.             outCtx.videoCodecCtx->max_b_frames = 2;
  356.         }
  357.  
  358.         if (outCtx.videoCodecCtx->codec_id == AV_CODEC_ID_MPEG1VIDEO)
  359.         {
  360.             outCtx.videoCodecCtx->mb_decision = 2;
  361.         }
  362.  
  363.         // Open codec
  364.         if (avcodec_open2(outCtx.videoCodecCtx, outCtx.videoCodec, 0) < 0)
  365.         {
  366.             cerr << "Can't open output video codec" << endl;
  367.             return 1;
  368.         }
  369.  
  370.         if (outCtx.videoCodecCtx->pix_fmt != inCtx.videoCodecCtx->pix_fmt)
  371.         {
  372.             outCtx.swsCtx = sws_getContext(inCtx.videoCodecCtx->width,
  373.                                            inCtx.videoCodecCtx->height,
  374.                                            inCtx.videoCodecCtx->pix_fmt,
  375.                                            outCtx.videoCodecCtx->width,
  376.                                            outCtx.videoCodecCtx->height,
  377.                                            outCtx.videoCodecCtx->pix_fmt,
  378.                                            SWS_BICUBIC, 0, 0, 0);
  379.             if (!outCtx.swsCtx)
  380.             {
  381.                 cerr << "Can't initialize video conversion context" << endl;
  382.                 return 1;
  383.             }
  384.         }
  385.     }
  386.  
  387.  
  388.     // Setup audio stream
  389.     if (inCtx.audioStreamIndex >= 0 && addStream(outCtx, AVMEDIA_TYPE_AUDIO) >= 0)
  390.     {
  391.         outCtx.audioStream->id = 1; // WHAT IS IT???
  392.  
  393.         outCtx.audioCodecCtx->sample_fmt     = inCtx.audioCodecCtx->sample_fmt;
  394.         outCtx.audioCodecCtx->bit_rate       = inCtx.audioCodecCtx->bit_rate;
  395.         outCtx.audioCodecCtx->sample_rate    = inCtx.audioCodecCtx->sample_rate;
  396.         outCtx.audioCodecCtx->channels       = inCtx.audioCodecCtx->channels;
  397.         outCtx.audioCodecCtx->channel_layout = inCtx.audioCodecCtx->channel_layout;
  398.  
  399.         // Open codec
  400.         if (avcodec_open2(outCtx.audioCodecCtx, outCtx.audioCodec, 0) < 0)
  401.         {
  402.             cerr << "Can't open output audio codec" << endl;
  403.             return 1;
  404.         }
  405.     }
  406.  
  407.     av_dump_format(outCtx.formatCtx, 0, outCtx.resource.c_str(), 1);
  408.  
  409.     stat = avio_open2(&outCtx.formatCtx->pb, outCtx.resource.c_str(), AVIO_FLAG_WRITE, 0, 0);
  410.     if (stat < 0)
  411.     {
  412.         cerr << "Can't open output file: " << outCtx.resource << endl;
  413.         return 1;
  414.     }
  415.  
  416.     // write header
  417.     if (avformat_write_header(outCtx.formatCtx, 0) < 0)
  418.     {
  419.         cerr << "Can't write header to output file" << endl;
  420.         return 1;
  421.     }
  422.  
  423.  
  424.     ////
  425.     //// Transcode
  426.     ////
  427.  
  428.     cout << "streams: " << inCtx.videoStreamIndex << "/" << inCtx.audioStreamIndex << endl;
  429.     cout << "streams: " << outCtx.videoStreamIndex << "/" << outCtx.audioStreamIndex << endl;
  430.  
  431.     AVFrame *frame      = avcodec_alloc_frame();
  432.     AVFrame *videoFrame = 0;
  433.  
  434.     if (outCtx.swsCtx)
  435.     {
  436.         videoFrame = allocVideoFrame(outCtx.videoCodecCtx->pix_fmt,
  437.                                      outCtx.videoCodecCtx->width,
  438.                                      outCtx.videoCodecCtx->height);
  439.     }
  440.  
  441.  
  442.     AVPacket pkt;
  443.     av_init_packet(&pkt);
  444.     pkt.data = 0;
  445.     pkt.size = 0;
  446.  
  447.     int gotFrame;
  448.     uint64_t inputAudioSamples = 0;
  449.  
  450.     while (av_read_frame(inCtx.formatCtx, &pkt) >= 0)
  451.     {
  452.         stat = -1;
  453.         AVRational outPktTimeBase;
  454.         AVPacket outPkt;
  455.         int      gotPacket = 0;
  456.         av_init_packet(&outPkt);
  457.         outPkt.data = 0;
  458.         outPkt.size = 0;
  459.  
  460.         if (pkt.stream_index == inCtx.videoStreamIndex)
  461.         {
  462.             stat = avcodec_decode_video2(inCtx.videoCodecCtx, frame, &gotFrame, &pkt);
  463.             if (stat < 0)
  464.             {
  465.                 cerr << "Can't decode video frame" << endl;
  466.                 return 1;
  467.             }
  468.  
  469.             if (gotFrame)
  470.             {
  471.                 cout << "video_frame coded_n:" << frame->coded_picture_number
  472.                      << " pts:" << av_ts2timestr(frame->pts, &inCtx.videoCodecCtx->time_base)
  473.                      << endl;
  474.  
  475.  
  476.                 if (outCtx.swsCtx)
  477.                 {
  478.                     sws_scale(outCtx.swsCtx,
  479.                               (const uint8_t * const *)frame->data, frame->linesize, 0, inCtx.videoCodecCtx->height,
  480.                               videoFrame->data, videoFrame->linesize);
  481.                 }
  482.                 else
  483.                 {
  484.                     videoFrame = frame;
  485.                 }
  486.  
  487.                 // Encode
  488.                 stat = avcodec_encode_video2(outCtx.videoCodecCtx, &outPkt, videoFrame, &gotPacket);
  489.  
  490.                 if (stat >= 0 && gotPacket)
  491.                 {
  492.                     if (outCtx.videoCodecCtx->coded_frame->pts != AV_NOPTS_VALUE)
  493.                     {
  494.                         outPkt.pts = av_rescale_q(outCtx.videoCodecCtx->coded_frame->pts,
  495.                                                   outCtx.videoCodecCtx->time_base,
  496.                                                   outCtx.videoStream->time_base);
  497.                     }
  498.  
  499.                     if (outCtx.videoCodecCtx->coded_frame->key_frame)
  500.                     {
  501.                         outPkt.flags |= AV_PKT_FLAG_KEY;
  502.                     }
  503.  
  504.                     outPkt.stream_index = outCtx.videoStreamIndex;
  505.                     outPktTimeBase = outCtx.videoStream->time_base;
  506.                 }
  507.             }
  508.         }
  509.         else if (pkt.stream_index == inCtx.audioStreamIndex)
  510.         {
  511.             stat = avcodec_decode_audio4(inCtx.audioCodecCtx, frame, &gotFrame, &pkt);
  512.             if (stat < 0)
  513.             {
  514.                 cerr << "Can't decode audio frame" << endl;
  515.                 return 1;
  516.             }
  517.  
  518.             if (gotFrame)
  519.             {
  520.                 if (frame->pts == AV_NOPTS_VALUE)
  521.                 {
  522.                     AVRational samplesRateInv = {1, outCtx.audioCodecCtx->sample_rate};
  523.                     int64_t pts = inputAudioSamples;
  524.                     frame->pts = av_rescale_q(pts, samplesRateInv, inCtx.audioCodecCtx->time_base);
  525.                 }
  526.  
  527.                 inputAudioSamples += frame->nb_samples;
  528.  
  529.                 cout << "audio_frame nb_samples:" << frame->nb_samples
  530.                      << " pts:" << av_ts2timestr(frame->pts, &inCtx.audioCodecCtx->time_base)
  531.                      << " timebase: " << inCtx.audioCodecCtx->time_base.num << "/" << inCtx.audioCodecCtx->time_base.den
  532.                      << endl;
  533.  
  534.                 // Encode
  535.                 stat = avcodec_encode_audio2(outCtx.audioCodecCtx, &outPkt, frame, &gotPacket);
  536.                 if (stat >= 0 && gotPacket)
  537.                 {
  538.                     outPkt.stream_index = outCtx.audioStreamIndex;
  539.                     outPktTimeBase = outCtx.audioStream->time_base;
  540.                 }
  541.             }
  542.  
  543.         }
  544.  
  545.         // Muxing
  546.         if (stat >= 0 && gotPacket && outPkt.data && outPkt.size > 0)
  547.         {
  548.             cout << "write frame st:" << outPkt.stream_index
  549.                  << " pts:" << av_ts2timestr(outPkt.pts, &outPktTimeBase)
  550.                  << endl;
  551.             stat = av_interleaved_write_frame(outCtx.formatCtx, &outPkt);
  552.             if (stat < 0)
  553.             {
  554.                 cerr << "Error while writing frame for stream: " << outPkt.stream_index << endl;
  555.                 return 1;
  556.             }
  557.         }
  558.     }
  559.  
  560.     // write trailer
  561.     av_write_trailer(outCtx.formatCtx);
  562.  
  563.     //
  564.     // Free resources
  565.     //
  566.  
  567.     // input
  568.     if (inCtx.videoStream)
  569.         avcodec_close(inCtx.videoStream->codec);
  570.     if (inCtx.audioStream)
  571.         avcodec_close(inCtx.audioStream->codec);
  572.  
  573.     avformat_close_input(&inCtx.formatCtx);
  574.  
  575.     // output
  576.     if (outCtx.videoStream)
  577.         avcodec_close(outCtx.videoStream->codec);
  578.     if (outCtx.audioStream)
  579.         avcodec_close(outCtx.audioStream->codec);
  580.  
  581.     for (uint i = 0; i < outCtx.formatCtx->nb_streams; ++i)
  582.     {
  583.         av_freep(&outCtx.formatCtx->streams[i]->codec);
  584.         av_freep(&outCtx.formatCtx->streams[i]);
  585.     }
  586.  
  587.     if (outCtx.swsCtx)
  588.     {
  589.         sws_freeContext(outCtx.swsCtx);
  590.         freeVideoFrame(&videoFrame);
  591.     }
  592.  
  593.     avio_close(outCtx.formatCtx->pb);
  594.  
  595.     av_free(outCtx.formatCtx);
  596.  
  597.  
  598.     return 0;
  599. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement