Guest User

Untitled

a guest
Nov 30th, 2016
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.90 KB | None | 0 0
  1. ======== encoder.cpp ======
  2.  (There is a 'encode.h' that looks just like you would expect)
  3.  
  4. #include "encoder.h"
  5. #include <algorithm>
  6. #include <iterator>
  7.  
  8. extern "C"
  9. {
  10. #include "libavcodec/avcodec.h"
  11. #include "libavdevice/avdevice.h"
  12. #include "libavfilter/avfilter.h"
  13. #include "libavformat/avformat.h"
  14. #include "libavutil/avutil.h"
  15. #include "libavutil/imgutils.h"
  16. #include "libswscale/swscale.h"
  17. #include "libswresample/swresample.h"
  18.  
  19. #define RES_NOT_MUL_OF_TWO 1
  20. #define COULD_NOT_FIND_VID_CODEC 2
  21. #define CONTEXT_CREATION_ERROR 3
  22. #define COULD_NOT_OPEN_VID_CODEC 4
  23. #define COULD_NOT_OPEN_FILE 5
  24. #define COULD_NOT_ALLOCATE_FRAME 6
  25. #define COULD_NOT_ALLOCATE_PIC_BUF 7
  26. #define ERROR_ENCODING_FRAME_SEND 8
  27. #define ERROR_ENCODING_FRAME_RECEIVE 9
  28. #define COULD_NOT_FIND_AUD_CODEC 10
  29. #define COULD_NOT_OPEN_AUD_CODEC 11
  30. #define COULD_NOT_ALL_RESMPL_CONTEXT 12
  31. #define FAILED_TO_INIT_RESMPL_CONTEXT 13
  32. #define COULD_NOT_ALLOC_SAMPLES 14
  33. #define COULD_NOT_CONVERT_AUD 15
  34. #define ERROR_ENCODING_SAMPLES_SEND 16
  35. #define ERROR_ENCODING_SAMPLES_RECEIVE 17
  36. #define ENCODED_VIDEO 18
  37. #define ENCODED_AUDIO 19
  38. #define ENCODED_AUDIO_AND_VIDEO 20
  39.  
  40.     AVCodec *vid_codec, *aud_codec;
  41.     AVCodecContext *vid_codec_context = NULL;
  42.     AVCodecContext *aud_codec_context = NULL;
  43.     AVFormatContext *outctx;
  44.     AVStream *video_st, *audio_st;
  45.     AVFrame *vid_frame, *aud_frame;
  46.     SwsContext *sws_ctx;
  47.     SwrContext *swr_ctx = NULL;
  48.  
  49.     int vid_frame_counter, aud_frame_counter;
  50.     int vid_width, vid_height;
  51.  
  52.     // Audio converting
  53.     //uint8_t **src_samples_data;
  54.     int src_samples_linesize;
  55.     //int src_nb_samples;
  56.     int max_dst_nb_samples;
  57.  
  58.     uint8_t **dst_samples_data;
  59.     int dst_samples_linesize;
  60.     int dst_samples_size;
  61.  
  62.     int initialize_encoding_def(int width, int height, int frame_rate, int bitrate, const char *filename)
  63.     {
  64.         if (width % 2 != 0 || height % 2 != 0)
  65.             return RES_NOT_MUL_OF_TWO;
  66.  
  67.         AVFormatContext *oc;
  68.  
  69.         AVCodecID vid_codec_id = AV_CODEC_ID_H264;
  70.         AVCodecID aud_codec_id = AV_CODEC_ID_AAC;
  71.         AVPixelFormat px_format = AV_PIX_FMT_YUV420P;
  72.         AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP;
  73.  
  74.         vid_width = width;
  75.         vid_height = height;
  76.  
  77.         int ret;
  78.  
  79.         avcodec_register_all();
  80.         av_register_all();
  81.  
  82.         // Fixup video codec
  83.         vid_codec = avcodec_find_encoder(vid_codec_id);
  84.         avcodec_register(vid_codec);
  85.  
  86.         if (!vid_codec)
  87.             return COULD_NOT_FIND_VID_CODEC;
  88.  
  89.         vid_codec_context = avcodec_alloc_context3(vid_codec);
  90.         if (!vid_codec_context)
  91.             return CONTEXT_CREATION_ERROR;
  92.  
  93.         vid_codec_context->bit_rate = bitrate;
  94.         vid_codec_context->width = width;
  95.         vid_codec_context->height = height;
  96.  
  97.         AVRational time_base;
  98.         time_base.num = 1;
  99.         time_base.den = frame_rate;
  100.         vid_codec_context->time_base = time_base;
  101.  
  102.         vid_codec_context->gop_size = 10;
  103.         vid_codec_context->max_b_frames = 1;
  104.         vid_codec_context->pix_fmt = px_format;
  105.         ret = av_opt_set(vid_codec_context->priv_data, "preset", "slow", 0);
  106.  
  107.         ret = avcodec_open2(vid_codec_context, vid_codec, NULL);
  108.         if (ret < 0)
  109.             return COULD_NOT_OPEN_VID_CODEC;
  110.  
  111.         outctx = avformat_alloc_context();
  112.         ret = avformat_alloc_output_context2(&outctx, NULL, "mp4", filename);
  113.  
  114.         outctx->video_codec = vid_codec;
  115.         outctx->video_codec_id = vid_codec_id;
  116.  
  117.         video_st = avformat_new_stream(outctx, vid_codec);
  118.  
  119.         video_st->codecpar->width = width;
  120.         video_st->codecpar->height = height;
  121.         video_st->codecpar->codec_id = vid_codec->id;
  122.         video_st->codecpar->codec_type = vid_codec->type;
  123.         video_st->codecpar->format = px_format;
  124.         video_st->codecpar->bit_rate = bitrate;
  125.         video_st->time_base = time_base;
  126.  
  127.         vid_frame = av_frame_alloc();
  128.  
  129.         if (!vid_frame)
  130.             return COULD_NOT_ALLOCATE_FRAME;
  131.  
  132.         vid_frame->format = vid_codec_context->pix_fmt;
  133.         vid_frame->width = vid_codec_context->width;
  134.         vid_frame->height = vid_codec_context->height;
  135.  
  136.         ret = av_image_alloc(vid_frame->data, vid_frame->linesize, vid_codec_context->width, vid_codec_context->height, vid_codec_context->pix_fmt, 32);
  137.         if (ret < 0)
  138.             return COULD_NOT_ALLOCATE_PIC_BUF;
  139.  
  140.         sws_ctx = sws_getContext(vid_codec_context->width, vid_codec_context->height,
  141.             AV_PIX_FMT_RGB24, vid_codec_context->width, vid_codec_context->height,
  142.             AV_PIX_FMT_YUV420P, 0, 0, 0, 0);
  143.  
  144.         vid_frame_counter = 0;
  145.  
  146.         // Fixup audio codec
  147.         aud_codec = avcodec_find_encoder(aud_codec_id);
  148.         avcodec_register(aud_codec);
  149.  
  150.         if (!aud_codec)
  151.             return COULD_NOT_FIND_AUD_CODEC;
  152.  
  153.         aud_codec_context = avcodec_alloc_context3(aud_codec);
  154.         if (!aud_codec_context)
  155.             return CONTEXT_CREATION_ERROR;
  156.  
  157.         /* select other audio parameters supported by the encoder */
  158.         aud_codec_context->bit_rate = 192000;
  159.         aud_codec_context->sample_rate = 48000;
  160.         aud_codec_context->sample_fmt = sample_fmt;
  161.         aud_codec_context->channel_layout = AV_CH_LAYOUT_STEREO;
  162.         aud_codec_context->channels = av_get_channel_layout_nb_channels(aud_codec_context->channel_layout);
  163.         //aud_codec_context->profile = FF_PROFILE_AAC_MAIN;
  164.  
  165.         aud_codec_context->codec = aud_codec;
  166.         aud_codec_context->codec_id = aud_codec_id;
  167.  
  168.         ret = avcodec_open2(aud_codec_context, aud_codec, NULL);
  169.  
  170.         if (ret < 0)
  171.             return COULD_NOT_OPEN_AUD_CODEC;
  172.  
  173.         outctx->audio_codec = aud_codec;
  174.         outctx->audio_codec_id = aud_codec_id;
  175.  
  176.         audio_st = avformat_new_stream(outctx, aud_codec);
  177.  
  178.         audio_st->codecpar->bit_rate = aud_codec_context->bit_rate;
  179.         audio_st->codecpar->sample_rate = aud_codec_context->sample_rate;
  180.         audio_st->codecpar->channels = aud_codec_context->channels;
  181.         audio_st->codecpar->channel_layout = aud_codec_context->channel_layout;
  182.         audio_st->codecpar->codec_id = aud_codec_id;
  183.         audio_st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
  184.         audio_st->codecpar->format = sample_fmt;
  185.         audio_st->codecpar->frame_size = aud_codec_context->frame_size;
  186.         audio_st->codecpar->block_align = aud_codec_context->block_align;
  187.         audio_st->codecpar->initial_padding = aud_codec_context->initial_padding;
  188.  
  189.         //audio_st->codec->frame_size
  190.  
  191.         av_dump_format(outctx, 0, filename, 1);
  192.  
  193.         if (!(outctx->oformat->flags & AVFMT_NOFILE))
  194.         {
  195.             if (avio_open(&outctx->pb, filename, AVIO_FLAG_WRITE) < 0)
  196.                 return COULD_NOT_OPEN_FILE;
  197.         }
  198.  
  199.         ret = avformat_write_header(outctx, NULL);
  200.  
  201.         aud_frame = av_frame_alloc();
  202.         aud_frame->nb_samples = aud_codec_context->frame_size;
  203.         aud_frame->format = aud_codec_context->sample_fmt;
  204.         aud_frame->channel_layout = aud_codec_context->channel_layout;
  205.  
  206.         int buffer_size = av_samples_get_buffer_size(NULL, aud_codec_context->channels, aud_codec_context->frame_size,
  207.             aud_codec_context->sample_fmt, 0);
  208.  
  209.         av_frame_get_buffer(aud_frame, buffer_size / 2);
  210.  
  211.         if (!aud_frame)
  212.             return COULD_NOT_ALLOCATE_FRAME;
  213.  
  214.         aud_frame_counter = 0;
  215.  
  216.         return 0;
  217.     }
  218.  
  219.     int write_interleaved_audio_samples(uint8_t **aud_samples)
  220.     {
  221.         int ret;
  222.  
  223.         aud_frame->data[0] = aud_samples[0];
  224.         aud_frame->data[1] = aud_samples[1];
  225.  
  226.         aud_frame->pts = aud_frame_counter++;
  227.  
  228.         ret = avcodec_send_frame(aud_codec_context, aud_frame);
  229.         if (ret < 0)
  230.             return ERROR_ENCODING_SAMPLES_SEND;
  231.  
  232.         AVPacket pkt;
  233.         av_init_packet(&pkt);
  234.         pkt.data = NULL;
  235.         pkt.size = 0;
  236.  
  237.         fflush(stdout);
  238.  
  239.         while (true)
  240.         {
  241.             ret = avcodec_receive_packet(aud_codec_context, &pkt);
  242.             if (!ret)
  243.             {
  244.                 av_packet_rescale_ts(&pkt, aud_codec_context->time_base, audio_st->time_base);
  245.  
  246.                 pkt.stream_index = audio_st->index;
  247.                 av_interleaved_write_frame(outctx, &pkt);
  248.                 av_packet_unref(&pkt);
  249.             }
  250.             if (ret == AVERROR(EAGAIN))
  251.                 break;
  252.             else if (ret < 0)
  253.                 return ERROR_ENCODING_SAMPLES_RECEIVE;
  254.             else
  255.                 break;
  256.         }
  257.  
  258.         return 0;
  259.     }
  260.  
  261.     int write_interleaved_video_frame(uint8_t* rgb24Data, int skipped_frames)
  262.     {
  263.         uint8_t * inData[1] = { rgb24Data };
  264.         int inLinesize[1] = { 3 * vid_codec_context->width };
  265.  
  266.         // Flips image
  267.         inData[0] += (vid_height - 1) * inLinesize[0];
  268.         inLinesize[0] *= -1;
  269.  
  270.         sws_scale(sws_ctx, inData, inLinesize, 0, vid_codec_context->height, vid_frame->data, vid_frame->linesize); // From RGB to YUV
  271.  
  272.         vid_frame_counter += skipped_frames;
  273.         vid_frame->pts = vid_frame_counter++;
  274.  
  275.         int ret = avcodec_send_frame(vid_codec_context, vid_frame);
  276.         if (ret < 0)
  277.             return ERROR_ENCODING_FRAME_SEND;
  278.  
  279.         AVPacket pkt;
  280.         av_init_packet(&pkt);
  281.         pkt.data = NULL;
  282.         pkt.size = 0;
  283.  
  284.         fflush(stdout);
  285.  
  286.         while (true)
  287.         {
  288.             ret = avcodec_receive_packet(vid_codec_context, &pkt);
  289.             if (!ret)
  290.             {
  291.                 av_packet_rescale_ts(&pkt, vid_codec_context->time_base, video_st->time_base);
  292.  
  293.                 pkt.stream_index = video_st->index;
  294.                 av_interleaved_write_frame(outctx, &pkt);
  295.                 av_packet_unref(&pkt);
  296.             }
  297.             if (ret == AVERROR(EAGAIN))
  298.                 break;
  299.             else if (ret < 0)
  300.                 return ERROR_ENCODING_FRAME_RECEIVE;
  301.             else
  302.                 break;
  303.         }
  304.  
  305.         return 0;
  306.     }
  307.  
  308.     int encode_frame_with_audio(uint8_t* rgb24Data, uint8_t **aud_samples, int skipped_frames)
  309.     {
  310.         int ret;
  311.  
  312.         double audio_time = audio_st ? av_stream_get_end_pts(audio_st) * av_q2d(audio_st->time_base) : 0.0;
  313.         double video_time = video_st ? av_stream_get_end_pts(video_st) * av_q2d(video_st->time_base) : 0.0;
  314.  
  315.         if (!video_st || (video_st && audio_st && audio_time < video_time))
  316.         {
  317.             ret = write_interleaved_audio_samples(aud_samples);
  318.             if (ret != 0)
  319.                 return ret;
  320.  
  321.             return ENCODED_AUDIO;
  322.         }
  323.         else
  324.         {
  325.             ret = write_interleaved_video_frame(rgb24Data, skipped_frames);
  326.             if (ret != 0)
  327.                 return ret;
  328.  
  329.             return ENCODED_VIDEO;
  330.         }
  331.     }
  332.  
  333.     int finish_video_and_audio_encoding()
  334.     {
  335.         AVPacket pkt;
  336.         av_init_packet(&pkt);
  337.         pkt.data = NULL;
  338.         pkt.size = 0;
  339.  
  340.         fflush(stdout);
  341.  
  342.         int ret = avcodec_send_frame(aud_codec_context, NULL);
  343.         if (ret < 0)
  344.             return ERROR_ENCODING_FRAME_SEND;
  345.  
  346.         while (true)
  347.         {
  348.             ret = avcodec_receive_packet(aud_codec_context, &pkt);
  349.             if (!ret)
  350.             {
  351.                 av_packet_rescale_ts(&pkt, aud_codec_context->time_base, audio_st->time_base);
  352.  
  353.                 pkt.stream_index = audio_st->index;
  354.                 av_interleaved_write_frame(outctx, &pkt);
  355.                 av_packet_unref(&pkt);
  356.             }
  357.             if (ret == AVERROR_EOF)
  358.                 break;
  359.             else if (ret < 0)
  360.                 return ERROR_ENCODING_FRAME_RECEIVE;
  361.         }
  362.  
  363.         av_init_packet(&pkt);
  364.         pkt.data = NULL;
  365.         pkt.size = 0;
  366.  
  367.         ret = avcodec_send_frame(vid_codec_context, NULL);
  368.         if (ret < 0)
  369.             return ERROR_ENCODING_FRAME_SEND;
  370.  
  371.         while (true)
  372.         {
  373.             ret = avcodec_receive_packet(vid_codec_context, &pkt);
  374.             if (!ret)
  375.             {
  376.                 av_packet_rescale_ts(&pkt, vid_codec_context->time_base, video_st->time_base);
  377.  
  378.                 pkt.stream_index = audio_st->index;
  379.                 av_interleaved_write_frame(outctx, &pkt);
  380.                 av_packet_unref(&pkt);
  381.             }
  382.             if (ret == AVERROR_EOF)
  383.                 break;
  384.             else if (ret < 0)
  385.                 return ERROR_ENCODING_FRAME_RECEIVE;
  386.         }
  387.  
  388.  
  389.         av_write_trailer(outctx);
  390.     }
  391.  
  392.     void cleanup()
  393.     {
  394.         if (vid_frame)
  395.         {
  396.             av_frame_free(&vid_frame);
  397.         }
  398.         if (aud_frame)
  399.         {
  400.             av_frame_free(&aud_frame);
  401.         }
  402.         if (outctx)
  403.         {
  404.             for (int i = 0; i < outctx->nb_streams; i++)
  405.                 av_freep(&outctx->streams[i]);
  406.  
  407.             avio_close(outctx->pb);
  408.             av_free(outctx);
  409.         }
  410.  
  411.         if (aud_codec_context)
  412.         {
  413.             avcodec_close(aud_codec_context);
  414.             av_free(aud_codec_context);
  415.         }
  416.  
  417.         if (vid_codec_context)
  418.         {
  419.             avcodec_close(vid_codec_context);
  420.             av_free(vid_codec_context);
  421.         }
  422.     }
  423. }
  424.  
  425.  
  426. ===== main.cpp =====
  427.  
  428. #include "encoder.h"
  429. extern "C"
  430. {
  431. #include "libavformat/avformat.h"
  432. }
  433. #include <math.h>
  434.  
  435. void get_frame(uint8_t* rgb24Data, int width, int height, int frame_Index, int frame_rate, int sec)
  436. {
  437.     for (int y = 0; y < height; y++)
  438.     {
  439.         for (int x = 0; x < width; x++)
  440.         {
  441.             int index = (y * width * 3) + (x * 3);
  442.             float value = (float)frame_Index / (float)(frame_rate * sec);
  443.             int rgb_value = (int)(value * 255);
  444.  
  445.             rgb24Data[index] = rgb_value;
  446.             rgb24Data[index + 1] = rgb_value;
  447.             rgb24Data[index + 2] = rgb_value;
  448.         }
  449.     }
  450. }
  451.  
  452. void get_audio_frame(float_t *left_samples, float_t *right_samples, int frame_size, float* t)
  453. {
  454.     int j, i;
  455.     float v;
  456.     for (j = 0; j < frame_size; j++)
  457.     {
  458.         v = sin(*t) * 0.5;
  459.         *left_samples = v;
  460.         *right_samples = v;
  461.  
  462.         left_samples++;
  463.         right_samples++;
  464.  
  465.         *t += M_PI_2 * 220 / frame_size;
  466.     }
  467. }
  468.  
  469. int main()
  470. {
  471.     int width = 640;
  472.     int height = 480;
  473.     int frame_rate = 30;
  474.     float t = 0;
  475.  
  476.     initialize_encoding_def(width, height, frame_rate, 1000000, "movie.mp4");
  477.  
  478.     int sec = 50;
  479.  
  480.     int tot = 3 * width * height;
  481.     uint8_t* rgb24Data = new uint8_t[tot];
  482.     float_t** aud_samples;
  483.     int src_samples_linesize;
  484.     int src_nb_samples = 1024;
  485.     int src_channels = 2;
  486.  
  487.     int ret = av_samples_alloc_array_and_samples((uint8_t***)&aud_samples, &src_samples_linesize, src_channels,
  488.         src_nb_samples, AV_SAMPLE_FMT_FLTP, 0);
  489.  
  490.     ret = 20;
  491.     for (size_t i = 0; i < frame_rate * sec; i++)
  492.     {
  493.         if (ret == 20 || ret == 19)
  494.             get_audio_frame(aud_samples[0], aud_samples[1], src_nb_samples, &t);
  495.         if (ret == 20 || ret == 18)
  496.             get_frame(rgb24Data, width, height, i, frame_rate, sec);
  497.  
  498.         ret = encode_frame_with_audio(rgb24Data, (uint8_t **)aud_samples, 0);
  499.     }
  500.  
  501.     finish_video_and_audio_encoding();
  502.     cleanup();
  503.  
  504.     return 0;
  505. }
Add Comment
Please, Sign In to add comment