Advertisement
Guest User

Opus Encoding to webm

a guest
Aug 1st, 2017
22
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.67 KB | None | 0 0
  1. #include "encoder.h"
  2. #include <algorithm>
  3. #include <iterator>
  4.  
  5. extern "C"
  6. {
  7. #include "libavcodec/avcodec.h"
  8. #include "libavdevice/avdevice.h"
  9. #include "libavfilter/avfilter.h"
  10. #include "libavformat/avformat.h"
  11. #include "libavutil/avutil.h"
  12. #include "libavutil/imgutils.h"
  13. #include "libswscale/swscale.h"
  14. #include "libswresample/swresample.h"
  15.  
  16.     enum InfoCodes
  17.     {
  18.         ENCODED_VIDEO,
  19.         ENCODED_AUDIO,
  20.         ENCODED_AUDIO_AND_VIDEO,
  21.         NOT_ENOUGH_AUDIO_DATA,
  22.     };
  23.  
  24.     enum ErrorCodes
  25.     {
  26.         RES_NOT_MUL_OF_TWO = -1,
  27.         ERROR_FINDING_VID_CODEC = -2,
  28.         ERROR_CONTEXT_CREATION = -3,
  29.         ERROR_CONTEXT_ALLOCATING = -4,
  30.         ERROR_OPENING_VID_CODEC = -5,
  31.         ERROR_OPENING_FILE = -6,
  32.         ERROR_ALLOCATING_FRAME = -7,
  33.         ERROR_ALLOCATING_PIC_BUF = -8,
  34.         ERROR_ENCODING_FRAME_SEND = -9,
  35.         ERROR_ENCODING_FRAME_RECEIVE = -10,
  36.         ERROR_FINDING_AUD_CODEC = -11,
  37.         ERROR_OPENING_AUD_CODEC = -12,
  38.         ERROR_INIT_RESMPL_CONTEXT = -13,
  39.         ERROR_ENCODING_SAMPLES_SEND = -14,
  40.         ERROR_ENCODING_SAMPLES_RECEIVE = -15,
  41.         ERROR_WRITING_HEADER = -16,
  42.         ERROR_INIT_AUDIO_RESPAMLER = -17,
  43.     };
  44.  
  45.     AVCodecID aud_codec_comp_id = AV_CODEC_ID_OPUS;
  46.     AVSampleFormat sample_fmt_comp = AV_SAMPLE_FMT_S16;
  47.  
  48.     AVCodecID aud_codec_id;
  49.     AVSampleFormat sample_fmt;
  50.  
  51.     char* compressed_cont = "webm";
  52.  
  53.     AVCodec *aud_codec = NULL;
  54.     AVCodecContext *aud_codec_context = NULL;
  55.     AVFormatContext *outctx;
  56.     AVStream *audio_st;
  57.     AVFrame *aud_frame;
  58.     SwrContext *audio_swr_ctx;
  59.     uint8_t **dst_data = NULL;
  60.     AVRational conv_time_base;
  61.  
  62.     int aud_frame_counter;
  63.     int dst_nb_samples, src_nb_samples, max_dst_nb_samples;;
  64.     int src_rate, dst_rate;
  65.     int dst_nb_channels;
  66.     int dst_linesize;
  67.  
  68.     void write_error_to_file(const char* name, int value)
  69.     {
  70.         int buf_size = 100;
  71.         char* buf = new char[buf_size];
  72.  
  73.         int ret = av_strerror(value, buf, buf_size);
  74.  
  75.         FILE *f;
  76.         fopen_s(&f, name, "w");
  77.         if (f != NULL)
  78.         {
  79.             if (ret != 0)
  80.                 fprintf(f, "Error erroring: , \n", ret);
  81.             else
  82.                 fprintf(f, "Error code: %s\n", buf);
  83.  
  84.             fclose(f);
  85.         }
  86.     }
  87.  
  88.     void write_value_to_file(const char* name, float value)
  89.     {
  90.         FILE *f;
  91.         fopen_s(&f, name, "w");
  92.         if (f != NULL)
  93.         {
  94.             fprintf(f, "Value: %f\n", value);
  95.  
  96.             fclose(f);
  97.         }
  98.     }
  99.  
  100.     char* concat(const char *s1, const char *s2)
  101.     {
  102.         char *result = (char*)malloc(strlen(s1) + strlen(s2) + 1);
  103.  
  104.         strcpy(result, s1);
  105.         strcat(result, s2);
  106.  
  107.         return result;
  108.     }
  109.  
  110.     int setup_audio_codec()
  111.     {
  112.         aud_codec_id = aud_codec_comp_id;
  113.         sample_fmt = sample_fmt_comp;
  114.  
  115.         // Fixup audio codec
  116.         if (aud_codec == NULL)
  117.         {
  118.             aud_codec = avcodec_find_encoder(aud_codec_id);
  119.             avcodec_register(aud_codec);
  120.         }
  121.  
  122.         if (!aud_codec)
  123.             return ERROR_FINDING_AUD_CODEC;
  124.  
  125.         return 0;
  126.     }
  127.  
  128.  
  129.     int initialize_audio_stream(AVFormatContext *local_outctx, int sample_rate, int per_frame_audio_samples, int audio_bitrate)
  130.     {
  131.         aud_codec_context = avcodec_alloc_context3(aud_codec);
  132.         if (!aud_codec_context)
  133.             return ERROR_CONTEXT_CREATION;
  134.  
  135.         /* select other audio parameters supported by the encoder */
  136.         aud_codec_context->bit_rate = audio_bitrate;
  137.         aud_codec_context->sample_rate = sample_rate;
  138.         aud_codec_context->sample_fmt = sample_fmt;
  139.         aud_codec_context->channel_layout = AV_CH_LAYOUT_STEREO;
  140.         aud_codec_context->channels = av_get_channel_layout_nb_channels(aud_codec_context->channel_layout);
  141.  
  142.         aud_codec_context->codec = aud_codec;
  143.         aud_codec_context->codec_id = aud_codec_id;
  144.  
  145.         AVRational time_base;
  146.         time_base.num = per_frame_audio_samples;
  147.         time_base.den = aud_codec_context->sample_rate;
  148.         aud_codec_context->time_base = time_base;
  149.  
  150.         int ret = avcodec_open2(aud_codec_context, aud_codec, NULL);
  151.  
  152.         if (ret < 0)
  153.             return ERROR_OPENING_AUD_CODEC;
  154.  
  155.         local_outctx->audio_codec = aud_codec;
  156.         local_outctx->audio_codec_id = aud_codec_id;
  157.  
  158.         audio_st = avformat_new_stream(local_outctx, aud_codec);
  159.  
  160.         avcodec_parameters_from_context(audio_st->codecpar, aud_codec_context);
  161.  
  162.         conv_time_base.num = aud_codec_context->frame_size;
  163.         conv_time_base.den = aud_codec_context->sample_rate;
  164.  
  165.         aud_frame = av_frame_alloc();
  166.         aud_frame->nb_samples = aud_codec_context->frame_size;
  167.         aud_frame->format = aud_codec_context->sample_fmt;
  168.         aud_frame->channel_layout = aud_codec_context->channel_layout;
  169.         aud_frame->sample_rate = aud_codec_context->sample_rate;
  170.  
  171.         int buffer_size;
  172.         if (aud_codec_context->frame_size == 0)
  173.         {
  174.             buffer_size = per_frame_audio_samples * 2 * 4;
  175.             aud_frame->nb_samples = per_frame_audio_samples;
  176.         }
  177.         else
  178.         {
  179.             buffer_size = av_samples_get_buffer_size(NULL, aud_codec_context->channels, aud_codec_context->frame_size,
  180.                 aud_codec_context->sample_fmt, 0);
  181.         }
  182.  
  183.         if (av_sample_fmt_is_planar(sample_fmt))
  184.             ret = av_frame_get_buffer(aud_frame, buffer_size / 2);
  185.         else
  186.             ret = av_frame_get_buffer(aud_frame, buffer_size);
  187.  
  188.         if (!aud_frame || ret < 0)
  189.             return ERROR_ALLOCATING_FRAME;
  190.  
  191.         audio_swr_ctx = swr_alloc();
  192.         if (!audio_swr_ctx)
  193.             return ERROR_INIT_AUDIO_RESPAMLER;
  194.  
  195.         /* set options */
  196.         av_opt_set_int(audio_swr_ctx, "in_channel_layout", aud_codec_context->channel_layout, 0);
  197.         av_opt_set_int(audio_swr_ctx, "in_sample_rate", sample_rate, 0);
  198.         av_opt_set_int(audio_swr_ctx, "in_frame_size", per_frame_audio_samples, 0);
  199.         av_opt_set_sample_fmt(audio_swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
  200.  
  201.         av_opt_set_int(audio_swr_ctx, "out_channel_layout", aud_codec_context->channel_layout, 0);
  202.         av_opt_set_int(audio_swr_ctx, "out_sample_rate", aud_codec_context->sample_rate, 0);
  203.         av_opt_set_int(audio_swr_ctx, "out_frame_size", aud_codec_context->frame_size, 0);
  204.         av_opt_set_sample_fmt(audio_swr_ctx, "out_sample_fmt", aud_codec_context->sample_fmt, 0);
  205.  
  206.         /* initialize the resampling context */
  207.         if ((ret = swr_init(audio_swr_ctx)) < 0)
  208.         {
  209.             return ERROR_INIT_AUDIO_RESPAMLER;
  210.         }
  211.  
  212.         dst_rate = aud_codec_context->sample_rate;
  213.         src_rate = sample_rate;
  214.  
  215.         src_nb_samples = per_frame_audio_samples;
  216.         dst_nb_samples = aud_codec_context->frame_size;
  217.  
  218.         max_dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
  219.  
  220.         dst_nb_channels = av_get_channel_layout_nb_channels(aud_codec_context->channel_layout);
  221.  
  222.         ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, sample_fmt, 0);
  223.  
  224.         aud_frame_counter = 0;
  225.  
  226.         return 0;
  227.     }
  228.  
  229.     int initialize_audio_only_encoding(int sample_rate, int per_frame_audio_samples, int audio_bitrate, const char *filename)
  230.     {
  231.         int ret;
  232.  
  233.         avcodec_register_all();
  234.         av_register_all();
  235.  
  236.         outctx = avformat_alloc_context();
  237.  
  238.         char* full_filename;
  239.         char* with_dot = concat(filename, ".");
  240.         full_filename = concat(with_dot, compressed_cont);
  241.         ret = avformat_alloc_output_context2(&outctx, NULL, compressed_cont, full_filename);
  242.  
  243.         free(with_dot);
  244.  
  245.         if (ret < 0)
  246.         {
  247.             free(full_filename);
  248.             return ERROR_CONTEXT_CREATION;
  249.         }
  250.  
  251.         ret = setup_audio_codec();
  252.         if (ret < 0)
  253.             return ret;
  254.  
  255.         // Setup Audio
  256.         ret = initialize_audio_stream(outctx, sample_rate, per_frame_audio_samples, audio_bitrate);
  257.         if (ret < 0)
  258.             return ret;
  259.  
  260.         av_dump_format(outctx, 0, full_filename, 1);
  261.  
  262.         if (!(outctx->oformat->flags & AVFMT_NOFILE))
  263.         {
  264.             if (avio_open(&outctx->pb, full_filename, AVIO_FLAG_WRITE) < 0)
  265.             {
  266.                 free(full_filename);
  267.                 return ERROR_OPENING_FILE;
  268.             }
  269.         }
  270.  
  271.  
  272.         free(full_filename);
  273.  
  274.         ret = avformat_write_header(outctx, NULL);
  275.         if (ret < 0)
  276.             return ERROR_WRITING_HEADER;
  277.  
  278.         return 0;
  279.     }
  280.  
  281.     int process_encode_loop(AVFormatContext *local_outctx, AVCodecContext *codec_context, AVStream *stream, AVRational time_base, bool flush)
  282.     {
  283.         int ret;
  284.  
  285.         AVPacket pkt;
  286.         av_init_packet(&pkt);
  287.         pkt.data = NULL;
  288.         pkt.size = 0;
  289.  
  290.         while (true)
  291.         {
  292.             ret = avcodec_receive_packet(codec_context, &pkt);
  293.             if (!ret)
  294.             {
  295.                 pkt.stream_index = stream->index;
  296.                 av_packet_rescale_ts(&pkt, time_base, stream->time_base);
  297.                 av_interleaved_write_frame(local_outctx, &pkt);
  298.  
  299.                 av_packet_unref(&pkt);
  300.             }
  301.  
  302.             if (ret == AVERROR(EAGAIN))
  303.                 break;
  304.             else if (ret == AVERROR_EOF)
  305.                 break;
  306.             else if (ret < 0)
  307.                 return ERROR_ENCODING_FRAME_RECEIVE;
  308.             else if (flush == false)
  309.                 break;
  310.         }
  311.  
  312.         return 0;
  313.     }
  314.  
  315.     int write_audio_frame(float_t *aud_sample)
  316.     {
  317.         int ret;
  318.         if (dst_nb_samples > max_dst_nb_samples)
  319.         {
  320.             av_free(&aud_frame->data[0]);
  321.             ret = av_samples_alloc(aud_frame->data, &dst_linesize, dst_nb_channels, dst_nb_samples, sample_fmt, 1);
  322.             if (ret < 0)
  323.                 return ERROR_INIT_AUDIO_RESPAMLER;
  324.  
  325.             max_dst_nb_samples = dst_nb_samples;
  326.         }
  327.  
  328.         ret = swr_convert(audio_swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)&aud_sample, src_nb_samples);
  329.         if (ret < 0)
  330.         {
  331.             return ERROR_INIT_AUDIO_RESPAMLER;
  332.         }
  333.  
  334.         aud_frame->data[0] = (uint8_t*)dst_data[0];
  335.         aud_frame->extended_data[0] = (uint8_t*)dst_data[0];
  336.  
  337.         aud_frame->pts = aud_frame_counter++;
  338.  
  339.         ret = avcodec_send_frame(aud_codec_context, aud_frame);
  340.  
  341.         if (ret < 0)
  342.         {
  343.             write_error_to_file("AVERROR.txt", ret);
  344.  
  345.             return ERROR_ENCODING_SAMPLES_SEND;
  346.         }
  347.  
  348.         ret = process_encode_loop(outctx, aud_codec_context, audio_st, conv_time_base, false);
  349.  
  350.         if (ret < 0)
  351.             return ERROR_ENCODING_SAMPLES_RECEIVE;
  352.  
  353.         return ENCODED_AUDIO;
  354.     }
  355.  
  356.     int finish_audio_encoding()
  357.     {
  358.         //fclose(dst_file);
  359.  
  360.         AVPacket pkt;
  361.         av_init_packet(&pkt);
  362.         pkt.data = NULL;
  363.         pkt.size = 0;
  364.  
  365.         fflush(stdout);
  366.  
  367.         int ret = avcodec_send_frame(aud_codec_context, NULL);
  368.         if (ret < 0)
  369.             return ERROR_ENCODING_FRAME_SEND;
  370.  
  371.         while (true)
  372.         {
  373.             ret = avcodec_receive_packet(aud_codec_context, &pkt);
  374.             if (!ret)
  375.             {
  376.                 if (pkt.pts != AV_NOPTS_VALUE)
  377.                     pkt.pts = av_rescale_q(pkt.pts, aud_codec_context->time_base, audio_st->time_base);
  378.                 if (pkt.dts != AV_NOPTS_VALUE)
  379.                     pkt.dts = av_rescale_q(pkt.dts, aud_codec_context->time_base, audio_st->time_base);
  380.  
  381.                 av_write_frame(outctx, &pkt);
  382.                 av_packet_unref(&pkt);
  383.             }
  384.             if (ret == -AVERROR(AVERROR_EOF))
  385.                 break;
  386.             else if (ret < 0)
  387.                 return ERROR_ENCODING_FRAME_RECEIVE;
  388.         }
  389.  
  390.         av_write_trailer(outctx);
  391.  
  392.         return 0;
  393.     }
  394.  
  395.     void cleanup()
  396.     {
  397.         if (aud_frame)
  398.         {
  399.             av_frame_free(&aud_frame);
  400.         }
  401.         if (outctx)
  402.         {
  403.             for (int i = 0; i < outctx->nb_streams; i++)
  404.                 av_freep(&outctx->streams[i]);
  405.  
  406.             avio_close(outctx->pb);
  407.             av_free(outctx);
  408.         }
  409.  
  410.         if (aud_codec_context)
  411.         {
  412.             avcodec_close(aud_codec_context);
  413.             av_free(aud_codec_context);
  414.         }
  415.     }
  416.  
  417.     void fill_samples(float_t *dst, int nb_samples, int nb_channels, int sample_rate, float_t *t)
  418.     {
  419.         int i, j;
  420.         float_t tincr = 1.0 / sample_rate;
  421.         const float_t c = 2 * M_PI * 440.0;
  422.         /* generate sin tone with 440Hz frequency and duplicated channels */
  423.         for (i = 0; i < nb_samples; i++) {
  424.             *dst = sin(c * *t);
  425.             for (j = 1; j < nb_channels; j++)
  426.                 dst[j] = dst[0];
  427.             dst += nb_channels;
  428.             *t += tincr;
  429.         }
  430.     }
  431.  
  432.     int main()
  433.     {
  434.         int width = 1920;
  435.         int height = 1080;
  436.         int frame_rate = 30;
  437.         float t = 0, tincr = 0, tincr2 = 0;
  438.  
  439.         int sec = 20;
  440.  
  441.         int tot = 3 * width * height;
  442.         uint8_t* rgb24Data = new uint8_t[tot];
  443.         float_t** aud_samples_planar;
  444.         int16_t** aud_samples_s16;
  445.         int src_samples_linesize;
  446.         int src_nb_samples = 1024;
  447.         int src_channels = 2;
  448.         int sample_rate = 48000;
  449.  
  450.         uint8_t **src_data = NULL;
  451.  
  452.         int ret;
  453.  
  454.         initialize_audio_only_encoding(48000, src_nb_samples, 256000, "only_sound");
  455.  
  456.         ret = av_samples_alloc_array_and_samples(&src_data, &src_samples_linesize, src_channels,
  457.             src_nb_samples, AV_SAMPLE_FMT_FLT, 0);
  458.  
  459.  
  460.         for (size_t i = 0; i < frame_rate * sec; i++)
  461.         {
  462.             fill_samples((float *)src_data[0], src_nb_samples, src_channels, sample_rate, &t);
  463.             write_audio_frame((float *)src_data[0]);
  464.         }
  465.  
  466.         finish_audio_encoding();
  467.  
  468.         cleanup();
  469.  
  470.         return 0;
  471.     }
  472. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement