Advertisement
Guest User

Untitled

a guest
Apr 1st, 2017
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 21.00 KB | None | 0 0
  1.  
  2. /*
  3. Makefile:
  4.  
  5. ---------------------------------------------------
  6. CC=g++
  7.  
  8. FFMPEG_LIBS=    libavdevice                        \
  9.                 libavformat                        \
  10.                 libavfilter                        \
  11.                 libavcodec                         \
  12.                 libswresample                      \
  13.                 libswscale                         \
  14.                 libavutil                          \
  15.  
  16. CPPFLAGS := -Wall -g -std=c++14 $(shell pkg-config --cflags $(FFMPEG_LIBS)) $(CPPFLAGS)
  17.  
  18. LDFLAGS=-g
  19. LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) -lm $(LDLIBS)
  20.  
  21. SOURCES=        MakeVideo                           \
  22.  
  23. OBJS=$(addsuffix .o,$(SOURCES))
  24.  
  25. all: $(OBJS) $(SOURCES)
  26. ---------------------------------------------------
  27.  
  28.  
  29. starts with: ./MakeVideo 1.mp4
  30.  
  31.  
  32. */
  33.  
  34.  
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <math.h>
  39.  
  40. extern "C" {
  41.     #include <libavutil/avassert.h>
  42.     #include <libavutil/channel_layout.h>
  43.     #include <libavutil/opt.h>
  44.     #include <libavutil/mathematics.h>
  45.     #include <libavutil/timestamp.h>
  46.     #include <libavformat/avformat.h>
  47.     #include <libswscale/swscale.h>
  48.     #include <libswresample/swresample.h>
  49.  
  50. };
  51.  
  52. #define     VIDEO_WIDTH         1280
  53. #define     VIDEO_HEIGHT        720
  54.  
  55. //#define       VIDEO_WIDTH         320
  56. //#define       VIDEO_HEIGHT        240
  57.  
  58. //#define       VIDEO_WIDTH         1920
  59. //#define       VIDEO_HEIGHT        1080
  60.  
  61.  
  62. #define     STREAM_DURATION     3.0
  63. #define     STREAM_FRAME_RATE   20
  64. #define     STREAM_PIX_FMT      AV_PIX_FMT_YUV420P /* default pix_fmt */
  65. //#define STREAM_PIX_FMT        AV_PIX_FMT_YUV422P
  66.  
  67. #define SCALE_FLAGS         SWS_BICUBIC
  68.  
  69.  
  70. #define CLIP(X) ( (X) > 255 ? 255 : (X) < 0 ? 0 : X)
  71.  
  72. // RGB -> YCbCr
  73. #define CRGB2Y(R, G, B)     CLIP((19595 * R + 38470 * G + 7471 * B ) >> 16)
  74. #define CRGB2Cb(R, G, B)    CLIP((36962 * (B - CLIP((19595 * R + 38470 * G + 7471 * B ) >> 16) ) >> 16) + 128)
  75. #define CRGB2Cr(R, G, B)    CLIP((46727 * (R - CLIP((19595 * R + 38470 * G + 7471 * B ) >> 16) ) >> 16) + 128)
  76.  
  77. // RGB -> YUV
  78. #define RGB2Y(R, G, B) CLIP(( (  66 * (R) + 129 * (G) +  25 * (B) + 128) >> 8) +  16)
  79. #define RGB2U(R, G, B) CLIP(( ( -38 * (R) -  74 * (G) + 112 * (B) + 128) >> 8) + 128)
  80. #define RGB2V(R, G, B) CLIP(( ( 112 * (R) -  94 * (G) -  18 * (B) + 128) >> 8) + 128)
  81.  
  82.  
  83. class VideoRenderer {
  84.  
  85.     private:
  86.    
  87.         typedef struct OutputStream { // a wrapper around a single output AVStream
  88.  
  89.             AVStream *st;
  90.             AVCodecContext *enc;
  91.  
  92.             int64_t next_pts; // pts of the next frame that will be generated
  93.             int samples_count;
  94.  
  95.             AVFrame *frame;
  96.             AVFrame *tmp_frame;
  97.  
  98.             float t, tincr, tincr2;
  99.  
  100.             struct SwsContext *sws_ctx;
  101.             struct SwrContext *swr_ctx;
  102.  
  103.         } OutputStream;
  104.    
  105.         struct SwsContext                           *sws_context = NULL;
  106.         //std::vector < std::vector < RGBColor > >  imageArr;
  107.  
  108.     public:
  109.    
  110.         void log_packet( const AVFormatContext *fmt_ctx, const AVPacket *pkt ) {
  111.  
  112.             AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
  113.             printf( "pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n", av_ts2str( pkt->pts ), av_ts2timestr( pkt->pts, time_base ), av_ts2str( pkt->dts ), av_ts2timestr( pkt->dts, time_base ), av_ts2str( pkt->duration ), av_ts2timestr( pkt->duration, time_base ), pkt->stream_index );
  114.            
  115.         }
  116.  
  117.         int write_frame( AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt ) {
  118.  
  119.             av_packet_rescale_ts( pkt, *time_base, st->time_base ); // rescale output packet timestamp values from codec to stream timebase
  120.             pkt->stream_index = st->index;
  121.  
  122.             log_packet( fmt_ctx, pkt ); // Write the compressed frame to the media file.
  123.             return av_interleaved_write_frame( fmt_ctx, pkt );
  124.            
  125.         }
  126.  
  127.         void add_stream( OutputStream *ost, AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id ) { // Add an output stream.
  128.  
  129.             AVCodecContext *c;
  130.             int i;
  131.  
  132.             *codec = avcodec_find_encoder( codec_id ); // find the encoder
  133.             if ( !( *codec ) ) {
  134.                 fprintf( stderr, "Could not find encoder for '%s'\n", avcodec_get_name( codec_id ) );
  135.                 exit( 1 );
  136.             }
  137.  
  138.             ost->st = avformat_new_stream( oc, NULL );
  139.             if ( !ost->st ) {
  140.                 fprintf( stderr, "Could not allocate stream\n" );
  141.                 exit( 1 );
  142.             }
  143.             ost->st->id = oc->nb_streams-1;
  144.             c = avcodec_alloc_context3( *codec );
  145.             if ( !c ) {
  146.                 fprintf( stderr, "Could not alloc an encoding context\n" );
  147.                 exit( 1 );
  148.             }
  149.             ost->enc = c;
  150.  
  151.             switch ( ( *codec )->type ) {
  152.             case AVMEDIA_TYPE_AUDIO:
  153.                 c->sample_fmt  = ( *codec )->sample_fmts ? ( *codec )->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
  154.                 c->bit_rate    = 64000;
  155.                 c->sample_rate = 44100;
  156.                 if ( ( *codec )->supported_samplerates ) {
  157.                     c->sample_rate = ( *codec )->supported_samplerates[0];
  158.                     for ( i = 0; ( *codec )->supported_samplerates[i]; i++ ) {
  159.                         if ( ( *codec )->supported_samplerates[i] == 44100 )
  160.                             c->sample_rate = 44100;
  161.                     }
  162.                 }
  163.                 c->channels         = av_get_channel_layout_nb_channels( c->channel_layout );
  164.                 c->channel_layout   = AV_CH_LAYOUT_STEREO;
  165.                 if ( ( *codec )->channel_layouts ) {
  166.                     c->channel_layout = ( *codec )->channel_layouts[0];
  167.                     for ( i = 0; ( *codec )->channel_layouts[i]; i++ ) {
  168.                         if ( ( *codec )->channel_layouts[i] == AV_CH_LAYOUT_STEREO )
  169.                             c->channel_layout = AV_CH_LAYOUT_STEREO;
  170.                     }
  171.                 }
  172.                 c->channels        = av_get_channel_layout_nb_channels( c->channel_layout );
  173.                 ost->st->time_base = ( AVRational ){ 1, c->sample_rate };
  174.                 break;
  175.  
  176.             case AVMEDIA_TYPE_VIDEO:
  177.                 c->codec_id = codec_id;
  178.  
  179.                 c->bit_rate         = 3400000;
  180.                 c->width            = VIDEO_WIDTH; //320; //1280;
  181.                 c->height           = VIDEO_HEIGHT; //240; //720;
  182.                 ost->st->time_base  = ( AVRational ){ 1, STREAM_FRAME_RATE }; // timebase: This is the fundamental unit of time ( in seconds ) in term of which frame timestamps are represented. For fixed-fps content, timebase should be 1/framerate and timestamp increments should be identical to 1.
  183.                 c->time_base        = ost->st->time_base;
  184.  
  185.                 c->gop_size         = 12; // emit one intra frame every twelve frames at most
  186.                 c->pix_fmt          = STREAM_PIX_FMT;
  187.                
  188.                 if ( c->codec_id == AV_CODEC_ID_MPEG2VIDEO ) {
  189.                     c->max_b_frames = 2; // just for testing, we also add B-frames
  190.                 }
  191.                    
  192.                 if ( c->codec_id == AV_CODEC_ID_MPEG1VIDEO ) {
  193.                     c->mb_decision = 2; // Needed to avoid using macroblocks in which some coeffs overflow. This does not happen with normal video, it just happens here as the motion of the chroma plane does not match the luma plane.
  194.                 }
  195.                
  196.             break;
  197.  
  198.             default:
  199.                 break;
  200.                
  201.             }
  202.  
  203.             if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //Some formats want stream headers to be separate.
  204.            
  205.         }
  206.  
  207.         AVFrame *alloc_audio_frame( enum AVSampleFormat sample_fmt, uint64_t channel_layout, int sample_rate, int nb_samples ) { // audio output
  208.  
  209.             AVFrame *frame = av_frame_alloc(  );
  210.             int ret;
  211.  
  212.             if ( !frame ) {
  213.                 fprintf( stderr, "Error allocating an audio frame\n" );
  214.                 exit( 1 );
  215.             }
  216.  
  217.             frame->format           = sample_fmt;
  218.             frame->channel_layout   = channel_layout;
  219.             frame->sample_rate      = sample_rate;
  220.             frame->nb_samples       = nb_samples;
  221.  
  222.             if ( nb_samples ) {
  223.                 ret = av_frame_get_buffer( frame, 0 );
  224.                 if ( ret < 0 ) {
  225.                     fprintf( stderr, "Error allocating an audio buffer\n" );
  226.                     exit( 1 );
  227.                 }
  228.             }
  229.  
  230.             return frame;
  231.            
  232.         }
  233.  
  234.         void open_audio( AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg ) {
  235.  
  236.             AVCodecContext *c;
  237.             int nb_samples;
  238.             int ret;
  239.             AVDictionary *opt = NULL;
  240.  
  241.             c = ost->enc;
  242.  
  243.             /* open it */
  244.             av_dict_copy( &opt, opt_arg, 0 );
  245.             ret = avcodec_open2( c, codec, &opt );
  246.             av_dict_free( &opt );
  247.             if ( ret < 0 ) {
  248.                 fprintf( stderr, "Could not open audio codec: %s\n", av_err2str( ret ) );
  249.                 exit( 1 );
  250.             }
  251.  
  252.             // init signal generator
  253.             ost->t          = 0;
  254.             ost->tincr      = 2 * M_PI * 110.0 / c->sample_rate;
  255.             ost->tincr2     = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate; // increment frequency by 110 Hz per second
  256.  
  257.             if ( c->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE ) nb_samples = 10000;
  258.             else nb_samples = c->frame_size;
  259.  
  260.             ost->frame     = alloc_audio_frame( c->sample_fmt, c->channel_layout, c->sample_rate, nb_samples );
  261.             ost->tmp_frame = alloc_audio_frame( AV_SAMPLE_FMT_S16, c->channel_layout, c->sample_rate, nb_samples );
  262.  
  263.             ret = avcodec_parameters_from_context( ost->st->codecpar, c ); // copy the stream parameters to the muxer
  264.             if ( ret < 0 ) {
  265.                 fprintf( stderr, "Could not copy the stream parameters\n" );
  266.                 exit( 1 );
  267.             }
  268.  
  269.                 ost->swr_ctx = swr_alloc(  ); //create resampler context
  270.                 if ( !ost->swr_ctx ) {
  271.                     fprintf( stderr, "Could not allocate resampler context\n" );
  272.                     exit( 1 );
  273.                 }
  274.  
  275.                 /* set options */
  276.                 av_opt_set_int       ( ost->swr_ctx, "in_channel_count",   c->channels,       0 );
  277.                 av_opt_set_int       ( ost->swr_ctx, "in_sample_rate",     c->sample_rate,    0 );
  278.                 av_opt_set_sample_fmt( ost->swr_ctx, "in_sample_fmt",      AV_SAMPLE_FMT_S16, 0 );
  279.                 av_opt_set_int       ( ost->swr_ctx, "out_channel_count",  c->channels,       0 );
  280.                 av_opt_set_int       ( ost->swr_ctx, "out_sample_rate",    c->sample_rate,    0 );
  281.                 av_opt_set_sample_fmt( ost->swr_ctx, "out_sample_fmt",     c->sample_fmt,     0 );
  282.  
  283.                 /* initialize the resampling context */
  284.                 if ( ( ret = swr_init( ost->swr_ctx ) ) < 0 ) {
  285.                     fprintf( stderr, "Failed to initialize the resampling context\n" );
  286.                     exit( 1 );
  287.                 }
  288.            
  289.         }
  290.  
  291.         AVFrame *get_audio_frame( OutputStream *ost ) { // Prepare a 16 bit dummy audio frame of 'frame_size' samples and 'nb_channels' channels.
  292.  
  293.             AVFrame *frame = ost->tmp_frame;
  294.             int j, i, v;
  295.             int16_t *q = ( int16_t* )frame->data[0];
  296.  
  297.             if ( av_compare_ts( ost->next_pts, ost->enc->time_base, STREAM_DURATION, ( AVRational ){ 1, 1 } ) >= 0 ) return NULL; // check if we want to generate more frames
  298.  
  299.             for ( j = 0; j < frame->nb_samples; j++ ) {
  300.            
  301.                 v = ( int )( sin( ost->t ) * 10000 );
  302.                
  303.                 for ( i = 0; i < ost->enc->channels; i++ ) *q++ = v;
  304.                
  305.                 ost->t     += ost->tincr;
  306.                 ost->tincr += ost->tincr2;
  307.                
  308.             }
  309.  
  310.             frame->pts      = ost->next_pts;
  311.             ost->next_pts   += frame->nb_samples;
  312.  
  313.             return frame;
  314.            
  315.         }
  316.  
  317.         int write_audio_frame( AVFormatContext *oc, OutputStream *ost ) { // encode one audio frame and send it to the muxer return 1 when encoding is finished, 0 otherwise
  318.  
  319.             AVCodecContext *c;
  320.             AVPacket pkt = { 0 }; // data and size must be 0;
  321.             AVFrame *frame;
  322.             int ret;
  323.             int got_packet;
  324.             int dst_nb_samples;
  325.  
  326.             av_init_packet( &pkt );
  327.             c = ost->enc;
  328.  
  329.             frame = get_audio_frame( ost );
  330.  
  331.             if ( frame ) {
  332.                     dst_nb_samples = av_rescale_rnd( swr_get_delay( ost->swr_ctx, c->sample_rate ) + frame->nb_samples, c->sample_rate, c->sample_rate, AV_ROUND_UP ); // convert samples from native format to destination codec format, using the resampler compute destination number of samples
  333.                     av_assert0( dst_nb_samples == frame->nb_samples );
  334.  
  335.                 ret = av_frame_make_writable( ost->frame ); // when we pass a frame to the encoder, it may keep a reference to it internally; make sure we do not overwrite it here
  336.                 if ( ret < 0 ) exit( 1 );
  337.  
  338.                     ret = swr_convert( ost->swr_ctx, ost->frame->data, dst_nb_samples, ( const uint8_t ** )frame->data, frame->nb_samples ); // convert to destination format
  339.                     if ( ret < 0 ) {
  340.                         fprintf( stderr, "Error while converting\n" );
  341.                         exit( 1 );
  342.                     }
  343.                     frame = ost->frame;
  344.  
  345.                 frame->pts = av_rescale_q( ost->samples_count, ( AVRational ){1, c->sample_rate}, c->time_base );
  346.                 ost->samples_count += dst_nb_samples;
  347.             }
  348.  
  349.             ret = avcodec_encode_audio2( c, &pkt, frame, &got_packet );
  350.             if ( ret < 0 ) {
  351.                 fprintf( stderr, "Error encoding audio frame: %s\n", av_err2str( ret ) );
  352.                 exit( 1 );
  353.             }
  354.  
  355.             if ( got_packet ) {
  356.                 ret = write_frame( oc, &c->time_base, ost->st, &pkt );
  357.                 if ( ret < 0 ) {
  358.                     fprintf( stderr, "Error while writing audio frame: %s\n",
  359.                             av_err2str( ret ) );
  360.                     exit( 1 );
  361.                 }
  362.             }
  363.  
  364.             return ( frame || got_packet ) ? 0 : 1;
  365.         }
  366.  
  367.         /**************************************************************/
  368.         /* video output */
  369.  
  370.         AVFrame *alloc_picture( enum AVPixelFormat pix_fmt, int width, int height ) {
  371.  
  372.             AVFrame *picture;
  373.             int ret;
  374.  
  375.             picture = av_frame_alloc(  );
  376.             if ( !picture )
  377.                 return NULL;
  378.  
  379.             picture->format = pix_fmt;
  380.             picture->width  = width;
  381.             picture->height = height;
  382.  
  383.             ret = av_frame_get_buffer( picture, 32 ); // allocate the buffers for the frame data
  384.             if ( ret < 0 ) {
  385.                 fprintf( stderr, "Could not allocate frame data.\n" );
  386.                 exit( 1 );
  387.             }
  388.  
  389.             return picture;
  390.            
  391.         }
  392.  
  393.         void open_video( AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg ) {
  394.        
  395.             int ret;
  396.             AVCodecContext *c = ost->enc;
  397.             AVDictionary *opt = NULL;
  398.  
  399.             av_dict_copy( &opt, opt_arg, 0 );
  400.  
  401.             ret = avcodec_open2( c, codec, &opt ); // open the codec
  402.             av_dict_free( &opt );
  403.             if ( ret < 0 ) {
  404.                 fprintf( stderr, "Could not open video codec: %s\n", av_err2str( ret ) );
  405.                 exit( 1 );
  406.             }
  407.  
  408.             ost->frame = alloc_picture( c->pix_fmt, c->width, c->height ); // allocate and init a re-usable frame
  409.             if ( !ost->frame ) {
  410.                 fprintf( stderr, "Could not allocate video frame\n" );
  411.                 exit( 1 );
  412.             }
  413.  
  414.             ost->tmp_frame = NULL;
  415.             if ( c->pix_fmt != AV_PIX_FMT_YUV420P ) { // If the output format is not YUV420P, then a temporary YUV420P picture is needed too. It is then converted to the required output format.
  416.                 ost->tmp_frame = alloc_picture( AV_PIX_FMT_YUV420P, c->width, c->height );
  417.                 if ( !ost->tmp_frame ) {
  418.                     fprintf( stderr, "Could not allocate temporary picture\n" );
  419.                     exit( 1 );
  420.                 }
  421.             }
  422.  
  423.             ret = avcodec_parameters_from_context( ost->st->codecpar, c ); // copy the stream parameters to the muxer
  424.             if ( ret < 0 ) {
  425.                 fprintf( stderr, "Could not copy the stream parameters\n" );
  426.                 exit( 1 );
  427.             }
  428.            
  429.         }
  430.  
  431.         void ffmpeg_encoder_set_frame_yuv_from_rgb( AVFrame *frame ) {
  432.        
  433.             uint8_t *rgb = (uint8_t *) malloc( 3 * sizeof( uint8_t ) * frame->width * frame->height );
  434.            
  435.             int width = frame->width, height = frame->height;
  436.             int x, y, cur;
  437.             for (y = 0; y < height; y++) {
  438.                 for (x = 0; x < width; x++) {
  439.                     cur = 3 * (y * width + x);
  440.                     rgb[cur + 0] = 0;
  441.                     rgb[cur + 1] = 0;
  442.                     rgb[cur + 2] = 0;
  443.                     if ((frame->pts / 25) % 2 == 0) {
  444.                         if (y < height / 2) {
  445.                             if (x < width / 2) {
  446.                                 /* Black. */
  447.                             } else {
  448.                                 rgb[cur + 0] = 255;
  449.                             }
  450.                         } else {
  451.                             if (x < width / 2) {
  452.                                 rgb[cur + 1] = 255;
  453.                             } else {
  454.                                 rgb[cur + 2] = 255;
  455.                             }
  456.                         }
  457.                     } else {
  458.                         if (y < height / 2) {
  459.                             rgb[cur + 0] = 255;
  460.                             if (x < width / 2) {
  461.                                 rgb[cur + 1] = 255;
  462.                             } else {
  463.                                 rgb[cur + 2] = 255;
  464.                             }
  465.                         } else {
  466.                             if (x < width / 2) {
  467.                                 rgb[cur + 1] = 255;
  468.                                 rgb[cur + 2] = 255;
  469.                             } else {
  470.                                 rgb[cur + 0] = 255;
  471.                                 rgb[cur + 1] = 255;
  472.                                 rgb[cur + 2] = 255;
  473.                             }
  474.                         }
  475.                     }
  476.                 }
  477.             }
  478.            
  479.            
  480.            
  481.             sws_context = sws_getCachedContext( sws_context, frame->width, frame->height, AV_PIX_FMT_RGB24, frame->width, frame->height, AV_PIX_FMT_YUV420P, 0, 0, 0, 0 );
  482.            
  483.             const int inLinesize[ 1 ] = { 3 * frame->width }; // RGB stride
  484.             std::cout << "sws_scale BEGIN\n";
  485.             sws_scale( sws_context, ( const uint8_t * const * ) &rgb, inLinesize, 0, frame->height, frame->data, frame->linesize );
  486.             std::cout << "sws_scale END\n";
  487.            
  488.         }
  489.    
  490.         void fill_yuv_image( AVFrame *pict, int frame_index, int width, int height ) { // Prepare a dummy image.
  491.  
  492.             int ret = av_frame_make_writable( pict );     // when we pass a frame to the encoder, it may keep a reference to it internally; make sure we do not overwrite it here
  493.             if ( ret < 0 ) exit( 1 );
  494.  
  495.             int i = frame_index;
  496.            
  497.             ffmpeg_encoder_set_frame_yuv_from_rgb( pict );
  498.            
  499.             //!!! free( rgb );
  500.            
  501.         }
  502.  
  503.         AVFrame *get_video_frame( OutputStream *ost ) {
  504.  
  505.             AVCodecContext *c = ost->enc;
  506.  
  507.             if ( av_compare_ts( ost->next_pts, c->time_base, STREAM_DURATION, ( AVRational ){ 1, 1 } ) >= 0 ) return NULL; // check if we want to generate more frames
  508.  
  509.             if ( c->pix_fmt != AV_PIX_FMT_YUV420P ) {
  510.            
  511.                 if ( !ost->sws_ctx ) { // as we only generate a YUV420P picture, we must convert it to the codec pixel format if needed
  512.                     ost->sws_ctx = sws_getContext( c->width, c->height, AV_PIX_FMT_YUV420P, c->width, c->height, c->pix_fmt, SCALE_FLAGS, NULL, NULL, NULL );
  513.                     if ( !ost->sws_ctx ) {
  514.                         fprintf( stderr, "Could not initialize the conversion context\n" );
  515.                         exit( 1 );
  516.                     }
  517.                 }
  518.                 fill_yuv_image( ost->tmp_frame, ost->next_pts, c->width, c->height );
  519.                 sws_scale( ost->sws_ctx, ( const uint8_t * const * )ost->tmp_frame->data, ost->tmp_frame->linesize, 0, c->height, ost->frame->data, ost->frame->linesize );
  520.                
  521.             } else {
  522.                 fill_yuv_image( ost->frame, ost->next_pts, c->width, c->height );
  523.             }
  524.  
  525.             ost->frame->pts = ost->next_pts++;
  526.  
  527.             return ost->frame;
  528.            
  529.         }
  530.  
  531.         /*
  532.          * encode one video frame and send it to the muxer
  533.          * return 1 when encoding is finished, 0 otherwise
  534.          */
  535.         int write_video_frame( AVFormatContext *oc, OutputStream *ost ) {
  536.  
  537.             int ret;
  538.             AVCodecContext *c;
  539.             AVFrame *frame;
  540.             int got_packet = 0;
  541.             AVPacket pkt = { 0 };
  542.  
  543.             c = ost->enc;
  544.  
  545.             frame = get_video_frame( ost );
  546.  
  547.             av_init_packet( &pkt );
  548.  
  549.             /* encode the image */
  550.             ret = avcodec_encode_video2( c, &pkt, frame, &got_packet );
  551.             if ( ret < 0 ) {
  552.                 fprintf( stderr, "Error encoding video frame: %s\n", av_err2str( ret ) );
  553.                 exit( 1 );
  554.             }
  555.  
  556.             if ( got_packet ) {
  557.                 ret = write_frame( oc, &c->time_base, ost->st, &pkt );
  558.             } else {
  559.                 ret = 0;
  560.             }
  561.  
  562.             if ( ret < 0 ) {
  563.                 fprintf( stderr, "Error while writing video frame: %s\n", av_err2str( ret ) );
  564.                 exit( 1 );
  565.             }
  566.  
  567.             return ( frame || got_packet ) ? 0 : 1;
  568.            
  569.         }
  570.  
  571.         void close_stream( AVFormatContext *oc, OutputStream *ost ) {
  572.  
  573.             avcodec_free_context( &ost->enc );
  574.             av_frame_free( &ost->frame );
  575.             av_frame_free( &ost->tmp_frame );
  576.             sws_freeContext( ost->sws_ctx );
  577.             swr_free( &ost->swr_ctx );
  578.            
  579.         }
  580.    
  581.         void makeVideo( const char *filename ) {
  582.        
  583.             OutputStream video_st = { 0 }, audio_st = { 0 };
  584.             AVOutputFormat *fmt;
  585.             AVFormatContext *oc;
  586.             AVCodec *audio_codec, *video_codec;
  587.             int ret;
  588.             int have_video = 0, have_audio = 0;
  589.             int encode_video = 0, encode_audio = 0;
  590.             AVDictionary *opt = NULL;
  591.  
  592.             av_register_all(); // Initialize libavcodec, and register all codecs and formats.
  593.            
  594.             avformat_alloc_output_context2( &oc, NULL, NULL, filename ); // allocate the output media context
  595.             if ( !oc ) {
  596.                 printf( "Could not deduce output format from file extension: using MPEG.\n" );
  597.                 avformat_alloc_output_context2( &oc, NULL, "mpeg", filename );
  598.             }
  599.             if ( !oc ) exit( 0 );
  600.  
  601.             fmt = oc->oformat;
  602.  
  603.             if ( fmt->video_codec != AV_CODEC_ID_NONE ) { // Add the audio and video streams using the default format codecs and initialize the codecs.
  604.                 add_stream( &video_st, oc, &video_codec, fmt->video_codec );
  605.                 have_video = 1;
  606.                 encode_video = 1;
  607.             }
  608.             if ( fmt->audio_codec != AV_CODEC_ID_NONE ) {
  609.                 add_stream( &audio_st, oc, &audio_codec, fmt->audio_codec );
  610.                 have_audio = 1;
  611.                 encode_audio = 1;
  612.             }
  613.  
  614.             if ( have_video ) open_video( oc, video_codec, &video_st, opt ); // Now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers.
  615.             if ( have_audio ) open_audio( oc, audio_codec, &audio_st, opt );
  616.  
  617.             av_dump_format( oc, 0, filename, 1 );
  618.  
  619.             if ( !( fmt->flags & AVFMT_NOFILE ) ) { // open the output file, if needed
  620.                 ret = avio_open( &oc->pb, filename, AVIO_FLAG_WRITE );
  621.                 if ( ret < 0 ) {
  622.                     fprintf( stderr, "Could not open '%s': %s\n", filename, av_err2str( ret ) );
  623.                     exit( 0 );
  624.                 }
  625.             }
  626.  
  627.             ret = avformat_write_header( oc, &opt ); // Write the stream header, if any.
  628.             if ( ret < 0 ) {
  629.                 fprintf( stderr, "Error occurred when opening output file: %s\n", av_err2str( ret ) );
  630.                 exit( 0 );
  631.             }
  632.  
  633.             while ( encode_video || encode_audio ) {
  634.                 // select the stream to encode
  635.                 if ( encode_video && ( !encode_audio || av_compare_ts( video_st.next_pts, video_st.enc->time_base, audio_st.next_pts, audio_st.enc->time_base ) <= 0 ) ) {
  636.                     encode_video = !write_video_frame( oc, &video_st );
  637.                 } else {
  638.                     encode_audio = !write_audio_frame( oc, &audio_st );
  639.                 }
  640.             }
  641.  
  642.             av_write_trailer( oc ); // Write the trailer, if any. The trailer must be written before you close the CodecContexts open when you wrote the header; otherwise av_write_trailer(  ) may try to use memory that was freed on av_codec_close(  ).
  643.  
  644.             if ( have_video ) close_stream( oc, &video_st );
  645.             if ( have_audio ) close_stream( oc, &audio_st );
  646.  
  647.             if ( !( fmt->flags & AVFMT_NOFILE ) ) avio_closep( &oc->pb ); // Close the output file.
  648.  
  649.             avformat_free_context( oc ); // free the stream
  650.            
  651.         }
  652.  
  653. };
  654.  
  655. int main( int argc, char **argv ) {
  656.  
  657.     VideoRenderer vr;
  658.     vr.makeVideo( argv[ 1 ] );
  659.    
  660.     return 0;
  661.  
  662. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement