From patchwork Fri Apr 19 00:34:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Prete X-Patchwork-Id: 12804 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id A42F2448220 for ; Fri, 19 Apr 2019 03:35:14 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 82B8168830E; Fri, 19 Apr 2019 03:35:14 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from forward105p.mail.yandex.net (forward105p.mail.yandex.net [77.88.28.108]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E859B680818 for ; Fri, 19 Apr 2019 03:35:07 +0300 (EEST) Received: from mxback7j.mail.yandex.net (mxback7j.mail.yandex.net [IPv6:2a02:6b8:0:1619::110]) by forward105p.mail.yandex.net (Yandex) with ESMTP id A4E234D40583 for ; Fri, 19 Apr 2019 03:35:06 +0300 (MSK) Received: from smtp4o.mail.yandex.net (smtp4o.mail.yandex.net [2a02:6b8:0:1a2d::28]) by mxback7j.mail.yandex.net (nwsmtp/Yandex) with ESMTP id TZvitLMrMc-Z6GCkV16; Fri, 19 Apr 2019 03:35:06 +0300 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.com; s=mail; t=1555634106; bh=5VFulJziyl2OvHWrB3O+r2Nkm9pPWC4IB4J+bQqq/tk=; h=Subject:To:From:Message-Id:Cc:Date; b=LDtyMTrw74Bbpo1SH/B4hEHcl+t9QBGK81ktFKZKUjABe2ldiFnDWyMT9Gyt7+Ogi I78wmMFmd2909NdRrrwCzN0DLYBI1NrwZlCaIb0iAdJEOgM1WRvJ+yNpDy+dKb5BOD NOlGrZylQmFFQKWy1xec5trCQ5oaO/BKItNagIFY= Authentication-Results: mxback7j.mail.yandex.net; dkim=pass header.i=@yandex.com Received: by smtp4o.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id gzrxPDOhAu-Z41WUmeT; Fri, 19 Apr 2019 03:35:04 +0300 (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client certificate not present) From: Paolo Prete To: ffmpeg-devel@ffmpeg.org Date: Fri, 19 Apr 2019 02:34:50 +0200 Message-Id: <20190419003450.25021-1-paolopre976@yandex.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] New API usage example (it converts, encodes, muxes a raw audio file and shows how to use a custom callback for muxing, with an allocated I/O context) X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Paolo Prete MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" I think this example can be useful for showing all the above tasks in an ordered, easy and strictly sequential way, with a kind of input close to the user's needings. Signed-off-by: Paolo Prete --- configure | 2 + doc/examples/Makefile | 47 ++-- doc/examples/Makefile.example | 1 + doc/examples/convert_encode_mux_audio.c | 349 ++++++++++++++++++++++++ 4 files changed, 376 insertions(+), 23 deletions(-) create mode 100644 doc/examples/convert_encode_mux_audio.c diff --git a/configure b/configure index e10e2c2c46..1ae62ebdd5 100755 --- a/configure +++ b/configure @@ -1653,6 +1653,7 @@ COMPONENT_LIST=" EXAMPLE_LIST=" avio_dir_cmd_example avio_reading_example + convert_encode_mux_audio_example decode_audio_example decode_video_example demuxing_decoding_example @@ -3539,6 +3540,7 @@ yadif_cuda_filter_deps="ffnvcodec cuda_nvcc" # examples avio_dir_cmd_deps="avformat avutil" avio_reading_deps="avformat avcodec avutil" +convert_encode_mux_audio_example_deps="avformat avcodec swresample" decode_audio_example_deps="avcodec avutil" decode_video_example_deps="avcodec avutil" demuxing_decoding_example_deps="avcodec avformat avutil" diff --git a/doc/examples/Makefile b/doc/examples/Makefile index 2935424e54..7b7855fa27 100644 --- a/doc/examples/Makefile +++ b/doc/examples/Makefile @@ -1,26 +1,27 @@ -EXAMPLES-$(CONFIG_AVIO_DIR_CMD_EXAMPLE) += avio_dir_cmd -EXAMPLES-$(CONFIG_AVIO_READING_EXAMPLE) += avio_reading -EXAMPLES-$(CONFIG_DECODE_AUDIO_EXAMPLE) += decode_audio -EXAMPLES-$(CONFIG_DECODE_VIDEO_EXAMPLE) += decode_video -EXAMPLES-$(CONFIG_DEMUXING_DECODING_EXAMPLE) += demuxing_decoding -EXAMPLES-$(CONFIG_ENCODE_AUDIO_EXAMPLE) += encode_audio -EXAMPLES-$(CONFIG_ENCODE_VIDEO_EXAMPLE) += encode_video -EXAMPLES-$(CONFIG_EXTRACT_MVS_EXAMPLE) += extract_mvs -EXAMPLES-$(CONFIG_FILTER_AUDIO_EXAMPLE) += filter_audio -EXAMPLES-$(CONFIG_FILTERING_AUDIO_EXAMPLE) += filtering_audio -EXAMPLES-$(CONFIG_FILTERING_VIDEO_EXAMPLE) += filtering_video -EXAMPLES-$(CONFIG_HTTP_MULTICLIENT_EXAMPLE) += http_multiclient -EXAMPLES-$(CONFIG_HW_DECODE_EXAMPLE) += hw_decode -EXAMPLES-$(CONFIG_METADATA_EXAMPLE) += metadata -EXAMPLES-$(CONFIG_MUXING_EXAMPLE) += muxing -EXAMPLES-$(CONFIG_QSVDEC_EXAMPLE) += qsvdec -EXAMPLES-$(CONFIG_REMUXING_EXAMPLE) += remuxing -EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE) += resampling_audio -EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE) += scaling_video -EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac -EXAMPLES-$(CONFIG_TRANSCODING_EXAMPLE) += transcoding -EXAMPLES-$(CONFIG_VAAPI_ENCODE_EXAMPLE) += vaapi_encode -EXAMPLES-$(CONFIG_VAAPI_TRANSCODE_EXAMPLE) += vaapi_transcode +EXAMPLES-$(CONFIG_AVIO_DIR_CMD_EXAMPLE) += avio_dir_cmd +EXAMPLES-$(CONFIG_AVIO_READING_EXAMPLE) += avio_reading +EXAMPLES-$(CONFIG_CONVERT_ENCODE_MUX_AUDIO_EXAMPLE) += convert_encode_mux_audio +EXAMPLES-$(CONFIG_DECODE_AUDIO_EXAMPLE) += decode_audio +EXAMPLES-$(CONFIG_DECODE_VIDEO_EXAMPLE) += decode_video +EXAMPLES-$(CONFIG_DEMUXING_DECODING_EXAMPLE) += demuxing_decoding +EXAMPLES-$(CONFIG_ENCODE_AUDIO_EXAMPLE) += encode_audio +EXAMPLES-$(CONFIG_ENCODE_VIDEO_EXAMPLE) += encode_video +EXAMPLES-$(CONFIG_EXTRACT_MVS_EXAMPLE) += extract_mvs +EXAMPLES-$(CONFIG_FILTER_AUDIO_EXAMPLE) += filter_audio +EXAMPLES-$(CONFIG_FILTERING_AUDIO_EXAMPLE) += filtering_audio +EXAMPLES-$(CONFIG_FILTERING_VIDEO_EXAMPLE) += filtering_video +EXAMPLES-$(CONFIG_HTTP_MULTICLIENT_EXAMPLE) += http_multiclient +EXAMPLES-$(CONFIG_HW_DECODE_EXAMPLE) += hw_decode +EXAMPLES-$(CONFIG_METADATA_EXAMPLE) += metadata +EXAMPLES-$(CONFIG_MUXING_EXAMPLE) += muxing +EXAMPLES-$(CONFIG_QSVDEC_EXAMPLE) += qsvdec +EXAMPLES-$(CONFIG_REMUXING_EXAMPLE) += remuxing +EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE) += resampling_audio +EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE) += scaling_video +EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac +EXAMPLES-$(CONFIG_TRANSCODING_EXAMPLE) += transcoding +EXAMPLES-$(CONFIG_VAAPI_ENCODE_EXAMPLE) += vaapi_encode +EXAMPLES-$(CONFIG_VAAPI_TRANSCODE_EXAMPLE) += vaapi_transcode EXAMPLES := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)$(EXESUF)) EXAMPLES_G := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)_g$(EXESUF)) diff --git a/doc/examples/Makefile.example b/doc/examples/Makefile.example index 6428154c51..04e5c902a8 100644 --- a/doc/examples/Makefile.example +++ b/doc/examples/Makefile.example @@ -15,6 +15,7 @@ EXAMPLES= avio_dir_cmd \ avio_reading \ decode_audio \ decode_video \ + convert_encode_mux_audio \ demuxing_decoding \ encode_audio \ encode_video \ diff --git a/doc/examples/convert_encode_mux_audio.c b/doc/examples/convert_encode_mux_audio.c new file mode 100644 index 0000000000..c8ad3ec4ef --- /dev/null +++ b/doc/examples/convert_encode_mux_audio.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2019 Paolo Prete (paolopr976@gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * @file + * API example for converting, encoding and muxing raw audio files. + * This example reads a raw audio input file, converts it to a sample format accepted by + * a given encoder, performs encoding and puts the encoded frames into a muxing container. + * The encoded stream is written to a file named "outfile". + * It can be adapted, with few changes, to a custom raw audio source (i.e: a live one). + * It uses a custom I/O write callback (write_muxed_data()) in order to show how to access + * muxed packets written in memory, before they are written to the output file. + * + * The raw input audio file can be created with: + * + * ffmpeg -i some_audio_file -f f32le -acodec pcm_f32le -ac 2 -ar 48000 raw_audio_file.raw + * + * @example convert_encode_mux_audio.c + */ + +#include +#include +#include +#include + +// Customizable parameters +#define SAMPLE_RATE 48000 +#define ENCODER_ID AV_CODEC_ID_OPUS +#define ENCODER_BITRATE 64000 +#define INPUT_SAMPLE_FMT AV_SAMPLE_FMT_FLT +#define OUTPUT_SAMPLE_FMT AV_SAMPLE_FMT_S16 +#define INPUT_CHANNELS 2 +#define OUTPUT_CHANNELS 2 + +static int encoded_pkt_counter = 1; + +static int write_muxed_data(void *opaque, uint8_t *data, int size) +{ + FILE *encoded_audio_file = (FILE *)opaque; + fwrite(data, 1, size, encoded_audio_file); //(h) + return size; +} + +static int mux_encoded_packet (AVPacket *encoded_audio_packet, AVFormatContext *out_container_ctx) +{ + int ret_val; + if ((ret_val = av_write_frame(out_container_ctx, encoded_audio_packet)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Error calling av_write_frame() (error '%s')\n", av_err2str(ret_val)); + } else { + av_log(NULL, AV_LOG_INFO, "Encoded packet %d, size=%d, pts_time=%s\n", + encoded_pkt_counter, encoded_audio_packet->size, + av_ts2timestr(encoded_audio_packet->pts, &out_container_ctx->streams[0]->time_base)); + } + return ret_val; +} + +static int check_if_samplerate_is_supported(AVCodec *audio_codec, int samplerate) +{ + const int *samplerates_list = audio_codec->supported_samplerates; + while (*samplerates_list) { + if (*samplerates_list == samplerate) + return 0; + samplerates_list++; + } + return 1; +} + +int main(int argc, char **argv) +{ + FILE *input_audio_file = NULL, *encoded_audio_file = NULL; + AVCodec *audio_codec = NULL; + AVCodecContext *audio_encoder_ctx = NULL; + AVFrame *input_audio_frame = NULL, *converted_audio_frame = NULL; + SwrContext *audio_convert_context = NULL; + AVOutputFormat *out_container = NULL; + AVFormatContext *out_container_ctx = NULL; + uint8_t *out_container_buffer = NULL; + size_t out_container_buffer_size = 4096; + AVIOContext *avio_ctx = NULL; + AVStream *out_stream = NULL; + AVPacket *encoded_audio_packet = NULL; + int ret_val = 0; + int audio_bytes_to_encode; + + if (argc != 3) { + printf("Usage: %s , \n", argv[0]); + return 1; + } + + input_audio_file = fopen(argv[1], "rb"); + if (!input_audio_file) { + av_log(NULL, AV_LOG_ERROR, "Could not open input audio file\n"); + return AVERROR_EXIT; + } + + encoded_audio_file = fopen("outfile", "wb"); + if (!encoded_audio_file) { + av_log(NULL, AV_LOG_ERROR, "Could not open output audio file\n"); + fclose(input_audio_file); + return AVERROR_EXIT; + } + + /** + * Allocate the encoder's context and open the encoder + */ + audio_codec = avcodec_find_encoder(ENCODER_ID); + if (!audio_codec) { + av_log(NULL, AV_LOG_ERROR, "Could not find encoder's codec\n"); + ret_val = AVERROR_EXIT; + goto end; + } + if ((ret_val = check_if_samplerate_is_supported(audio_codec, SAMPLE_RATE)) != 0) { + av_log(NULL, AV_LOG_ERROR, "Audio codec doesn't support input samplerate %d\n", SAMPLE_RATE); + goto end; + } + audio_encoder_ctx = avcodec_alloc_context3(audio_codec); + if (!audio_codec) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate the encoding context\n"); + ret_val = AVERROR_EXIT; + goto end; + } + audio_encoder_ctx->sample_fmt = OUTPUT_SAMPLE_FMT; + audio_encoder_ctx->bit_rate = ENCODER_BITRATE; + audio_encoder_ctx->sample_rate = SAMPLE_RATE; + audio_encoder_ctx->channels = OUTPUT_CHANNELS; + audio_encoder_ctx->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS); + audio_encoder_ctx->time_base = (AVRational){1, SAMPLE_RATE}; + audio_encoder_ctx->codec_type = AVMEDIA_TYPE_AUDIO ; + if ((ret_val = avcodec_open2(audio_encoder_ctx, audio_codec, NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Could not open input codec (error '%s')\n", av_err2str(ret_val)); + goto end; + } + + /** + * Allocate an AVFrame which will be filled with the input file's data. + */ + if (!(input_audio_frame = av_frame_alloc())) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate input frame\n"); + ret_val = AVERROR(ENOMEM); + goto end; + } + input_audio_frame->nb_samples = audio_encoder_ctx->frame_size; + input_audio_frame->format = INPUT_SAMPLE_FMT; + input_audio_frame->channels = INPUT_CHANNELS; + input_audio_frame->sample_rate = SAMPLE_RATE; + input_audio_frame->channel_layout = av_get_default_channel_layout(INPUT_CHANNELS); + // Allocate the frame's data buffer + if ((ret_val = av_frame_get_buffer(input_audio_frame, 0)) < 0) { + av_log(NULL, AV_LOG_ERROR, + "Could not allocate container for input frame samples (error '%s')\n", av_err2str(ret_val)); + ret_val = AVERROR(ENOMEM); + goto end; + } + + /** + * Input data must be converted in the right format required by the encoder. + * We allocate a SwrContext and an AVFrame (which will contain the converted samples) for this task. + * The AVFrame will feed the encoding function (avcodec_send_frame()) + */ + audio_convert_context = swr_alloc_set_opts(NULL, + av_get_default_channel_layout(OUTPUT_CHANNELS), + OUTPUT_SAMPLE_FMT, + SAMPLE_RATE, + av_get_default_channel_layout(INPUT_CHANNELS), + INPUT_SAMPLE_FMT, + SAMPLE_RATE, + 0, + NULL); + if (!audio_convert_context) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate resample context\n"); + ret_val = AVERROR(ENOMEM); + goto end; + } + if (!(converted_audio_frame = av_frame_alloc())) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate resampled frame\n"); + ret_val = AVERROR(ENOMEM); + goto end; + } + converted_audio_frame->nb_samples = audio_encoder_ctx->frame_size; + converted_audio_frame->format = audio_encoder_ctx->sample_fmt; + converted_audio_frame->channels = audio_encoder_ctx->channels; + converted_audio_frame->channel_layout = audio_encoder_ctx->channel_layout; + converted_audio_frame->sample_rate = SAMPLE_RATE; + if ((ret_val = av_frame_get_buffer(converted_audio_frame, 0)) < 0) { + av_log(NULL, AV_LOG_ERROR, + "Could not allocate a buffer for resampled frame samples (error '%s')\n", av_err2str(ret_val)); + goto end; + } + + /** + * Create the output container for the encoded frames + */ + out_container = av_guess_format(argv[2], NULL, NULL); + if (!out_container) { + av_log(NULL, AV_LOG_ERROR, "Could not find output format\n"); + ret_val = AVERROR_EXIT; + goto end; + } + if ((ret_val = avformat_alloc_output_context2(&out_container_ctx, out_container, "", NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Could not create output context (error '%s')\n", av_err2str(ret_val)); + goto end; + } + if (!(out_container_buffer = av_malloc(out_container_buffer_size))) { + av_log(NULL, AV_LOG_ERROR, "Could not allocate a buffer for the I/O output context\n"); + ret_val = AVERROR(ENOMEM); + goto end; + } + + /** + * Create an I/O context for the muxer's container with a write callback (write_muxed_data()), + * so that muxed data will be accessed through this function and can be managed by the user. + */ + if (!(avio_ctx = avio_alloc_context(out_container_buffer, out_container_buffer_size, + 1, encoded_audio_file, NULL, + &write_muxed_data, NULL))) { + av_log(NULL, AV_LOG_ERROR, "Could not create I/O output context\n"); + ret_val = AVERROR_EXIT; + goto end; + } + + /** + * Link the container's context to the previous I/O context + */ + out_container_ctx->pb = avio_ctx; + if (!(out_stream = avformat_new_stream(out_container_ctx, NULL))) { + av_log(NULL, AV_LOG_ERROR, "Could not create new stream\n"); + ret_val = AVERROR(ENOMEM); + goto end; + } + out_stream->id = out_container_ctx->nb_streams-1; + + // Copy the encoder's parameters + avcodec_parameters_from_context(out_stream->codecpar, audio_encoder_ctx); + // Allocate the stream private data and write the stream header + if (avformat_write_header(out_container_ctx, NULL) < 0) { + av_log(NULL, AV_LOG_ERROR, "avformat_write_header() error\n"); + ret_val = AVERROR_EXIT; + goto end; + } + + /** + * (a) Fill the input frame's data buffer with input file data + * (b) Convert the input frame to output sample format + * (c) Assign a pts to the converted frame based on the number ot total samples read + * (d) Send the converted frame to the encoder + * (e) Get the encoded packet + * (f) Rescale the timestamps of the encoded packet to the muxer's timebase + * (g) Send the encoded packet, with rescaled timestamps, to the muxer + * (h) Muxed data is caught in write_muxed_data() callback (see above) and it is + * written to the output audio file + */ + encoded_audio_packet = av_packet_alloc(); + while (1) { + + audio_bytes_to_encode = fread(input_audio_frame->data[0], 1, + input_audio_frame->linesize[0], input_audio_file); //(a) + if (audio_bytes_to_encode != input_audio_frame->linesize[0]) { + break; + } else { + if (av_frame_make_writable(converted_audio_frame) < 0) { + av_log(NULL, AV_LOG_ERROR, "av_frame_make_writable() error\n"); + ret_val = AVERROR_EXIT; + goto end; + } + + if ((ret_val = swr_convert_frame(audio_convert_context, + converted_audio_frame, + (const AVFrame *)input_audio_frame)) != 0) { //(b) + av_log(NULL, AV_LOG_ERROR, + "Error resampling input audio frame (error '%s')\n", av_err2str(ret_val)); + goto end; + } + + converted_audio_frame->pts = converted_audio_frame->nb_samples*(encoded_pkt_counter-1); //(c) + + if ((ret_val = avcodec_send_frame(audio_encoder_ctx, converted_audio_frame)) == 0) //(d) + ret_val = avcodec_receive_packet(audio_encoder_ctx, encoded_audio_packet); //(e) + else { + av_log(NULL, AV_LOG_ERROR, + "Error encoding frame (error '%s')\n", av_err2str(ret_val)); + goto end; + } + + if (ret_val == 0) { + encoded_audio_packet->dts = encoded_audio_packet->pts; + av_packet_rescale_ts(encoded_audio_packet, audio_encoder_ctx->time_base, + out_container_ctx->streams[0]->time_base); //(f) + if ((ret_val = mux_encoded_packet(encoded_audio_packet, out_container_ctx)) < 0) //(g) + goto end; + encoded_pkt_counter++; + } else if (ret_val != AVERROR(EAGAIN)) { + av_log(NULL, AV_LOG_ERROR, + "Error receiving encoded packet (error '%s')\n", av_err2str(ret_val)); + goto end; + } + } + } + + // Flush cached packets + if ((ret_val = avcodec_send_frame(audio_encoder_ctx, NULL)) == 0) + do { + ret_val = avcodec_receive_packet(audio_encoder_ctx, encoded_audio_packet); + if (ret_val == 0) { + encoded_audio_packet->dts = encoded_audio_packet->pts; + av_packet_rescale_ts(encoded_audio_packet, audio_encoder_ctx->time_base, + out_container_ctx->streams[0]->time_base); + if ((ret_val = mux_encoded_packet(encoded_audio_packet, out_container_ctx)) < 0) + goto end; + encoded_pkt_counter++; + } + } while (ret_val == 0); + + av_write_trailer(out_container_ctx); + +end: + + fclose(input_audio_file); + fclose(encoded_audio_file); + avcodec_free_context(&audio_encoder_ctx); + av_frame_free(&input_audio_frame); + swr_free(&audio_convert_context); + av_frame_free(&converted_audio_frame); + avformat_free_context(out_container_ctx); + av_freep(&avio_ctx); + av_freep(&out_container_buffer); + av_packet_free(&encoded_audio_packet); + + return ret_val; + +}