From patchwork Mon Jun 6 17:40:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paolo Prete X-Patchwork-Id: 36080 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:6914:b0:82:6b11:2509 with SMTP id q20csp6377865pzj; Mon, 6 Jun 2022 10:36:16 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxJfZ1bslnNKHKpwWBE/Erm1z+TSrhcLiQgo/ByxdlIAdhbQ/bzWg4mf+hTxS+pzmt+RSa5 X-Received: by 2002:a17:906:acb:b0:709:d274:611b with SMTP id z11-20020a1709060acb00b00709d274611bmr22542046ejf.147.1654536976113; Mon, 06 Jun 2022 10:36:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1654536976; cv=none; d=google.com; s=arc-20160816; b=ZB1vqvlpEZNhN/OlMToCpXr384n6iE00qn2Noa9cE2+17FPowHDoBN/TBCHARnLaZ+ 8x66VP4K8TN+GU+LHGvGR634jIWp3r6AClbbzkTVpU0YacV8en41kDLHUKYqI0qVWwr7 VBWAlMehGVCOZ34aqlpk8KKrwVxg11f1EM5TPDF3ZUlx5aH+UlT7k+E8+DGSNlVsGXby K9/QV5avM7/e6aJS+D8hwnxyRBjdUOYfZTbg5Qm+NP0etXt3oUJrDr+WjTm9vftECCEf W8Bjt97qoMzPmlzhgHURg84QUoiiqs1s3VDo4O6HWyU+r4w4sWeflyFGPH7rGTJDK6EP u8rw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:references :mime-version:message-id:to:from:date:dkim-signature:delivered-to; bh=OpL1Qv1d2kcYqS31X07kVqNDqFcPwE2QzuLVq5FMyhk=; b=ZcLxSXjfcKR4YRjPcEvVwdEY/LqItNNwgbzxFRmFlBqKIjKQeV1E1/I7rd+284BWb5 tNloBvsvFC5bmjeA2Lon63Gdc3UDeVDxlNL6H1Er2hmEvtzzourjUkM2zAop12J77kAB 6UJosvgJpGzRv6VkVUeJbQmkJwoQrKBm43pkZN6mPmJIVd51m9jzWkEpGflNbBk1/zkD TqphNLWfASPMvQtZrUvy2RlphDaJsBlZ28dWP8bPK5sl/UK/Fz8tSTacBWI41hnNUbpf YPTB6q0ud/gg8D8yX+5aZ0d4g80v8JUtO+o20bElVe7oklxE5qMmvJ2CSk4BmT+IENOq vFhQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@yahoo.it header.s=s2048 header.b=R17z6dDU; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id h19-20020a05640250d300b004316f91d4dasi1778014edb.617.2022.06.06.10.36.14; Mon, 06 Jun 2022 10:36:16 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@yahoo.it header.s=s2048 header.b=R17z6dDU; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id E685868B57B; Mon, 6 Jun 2022 20:36:10 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from sonic309-25.consmr.mail.ir2.yahoo.com (sonic309-25.consmr.mail.ir2.yahoo.com [77.238.179.83]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 63EAD68B3A1 for ; Mon, 6 Jun 2022 20:36:03 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.it; s=s2048; t=1654536962; bh=qW0sWxN2oD8OpTwK8PwGxL0KJT4XGqzg8Zs8r2CXxzc=; h=Date:From:To:Subject:References:From:Subject:Reply-To; b=R17z6dDUgyF27VCuor98lfrJJI+7Dzmv2IHB1VH4fgGMCO1yOBdJttfOsnKw2fwN6sji/nB44sn+NkO2JuL7wA98kg+A4SSZPT9+J8F5p2rwbp5TSZYx0JXgXaPbuKcrC0HNSMvJZ7sVdgFASuOH+/xa5fB1IBjX+DlMYdud0c/0Ic3bFZ+ZRSrXoYL8+AGSSXDv0e60ppTvc/ouahtD713D7Jnjfjo3ukZcb8r8zK0QMvnRVA3ZDZA3cL0g7OFNZN4IqYGqKYsbGiRErjn0xzbuCqn9UW/IXDzjrLRTrmKpKt54cEWZgZ1Mp9bPLLTF5k8RCrO1TJXlYCiKSsD5YQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1654536962; bh=BTYrFthSpxXB5wC09pyIyyDUlxQ84upQybjAHx86aPx=; h=X-Sonic-MF:Date:From:To:Subject:From:Subject; b=oHQ5W4xDy7wastuORh94hFkWOhrwAVm/ePeJIEi/gSJUyAZOalP/XKcTYYZc7S4NnFGrjrn5dGl5aQ1DZ5Fml1OsxzaGZOrxV63Jdm974aqsEPctGLYMvUrrsA4mGvrYarsYvv/8pHIxfXOFw/noK7kadxQfQ/Ama20CZqtxxnWlbco47B9Kv4cvKwhsSJVk54IrWVFgKWHFDN4S3/jP7mHjLnpa1YJWsDyAqApOUZPd9+7lx0WuXCtME2VXosO9dDby9OHNR22KsHQW/3JZJ9fISdPh7SsoU7MGQ7f5pQnGWMYLtwjXLlTGIlx6OP7i0S6CtbspA24bwt4Vtrmofg== X-YMail-OSG: JAjTavsVM1n.b5ghywOwzESUQc0z6LVuOhl_UnV7SP6UNwCpeh.52Pr_0HU0I9f 3iAl2HJQ19GbB4zuQL8.gKY6Tz1fCSRZhIgVnASIA7VIXgUhrUDlrqZk.xJEhvYMF0vkhjneKUbx KeY.QA.2wTCh56.5xxs.AkyuWq8tcu0x_Z62DmfxeQhTbBam9xKvFnAIKYxUNbVeeXRW4F5NuEBI bwsIo7tfORGGZzZ5jSL5TO3rp8ew6TE1_OiGQDZSqC_ihDPZT1bBYOLrgRrzmWS8vuG31RZMSMf8 Ip6RErRczYdQXh_ZcPqyWIb76kArHSAt_sHgqPT1JSCSGlCj_J8FDRKURUnLP6mHQFvBq.oOFpT. .SsDC1vvn3AXg9AaKMZ53A.9spQNBthzFrZMUdq.i0G.rSkIdisw05QsYYNBAjMGwXCyBDnroUeN 6cDrGolAToVqH8L9jLX9vREnb2Jh_529LcZ3v4nOh5V8nFiBk1I7XXTqfWQafCbZJy0smNQAHRdZ RXbAHRGTkLb.Kdl9NDP8rH47zQqJAmvwf2jwBF85xyOELvcwXn65H0GSqtQrPyaZUcBe8QK_MS7j tVhgbQfqWUsZliQwSUqC3A3oHY4vs3PMKcYDTpTZNjxbV3O6YvHucdx1.yKFmBrh1bpxqcZgbA3Y WU.blBim7Zl9VzICibmnvAnJzDevO04yUP4T8Y8CBn6Y1u_a9G5.sNCBE_GrmeOrdz1xFCj1bEax RCNSGRJR5siBIyFwXWlP8fji2iFpuNqjM9aD9U8DBaVdsSoq1UHnp98lSpYVO8sjNm9O0.FSyUlD w97bX7p7loloh_4SgtVoOfaD8IyU9_NpUv.WKnNykFFKKiEufbqHKqetvU8oYzZFhMD1kIO9BOqX fUMLy50VgOSi3LrwXxzRCHAgLFXIimiqxyHi2_4gUW9W_VLG6ndLPAxnUc9I4b3eL2LHBcZTPzBZ nniWiC.IlpTVlpixBDqGtsHHc.58GM0PmxB7IWq9mELgx4ecS2mYJF8A_gePpJdO7fynf2g4JfJ7 e2Ok73drhbyFR_iGosqpXqRVfInbrAhCKtpxd8ibaubt2Xcud3IAFs0GjEkEfgdEsXpSlMxC5HnL jiLSUutYWVwkEFcOn9G2YXrlUpsQ26hIMJ_9St9fTF4lfwXJ6o16cuSlVVX5SkiGYOMd5NiO5w9R HGg13KzxBk4EujbQLyvpO0ilyj5sgG.8isCZVkYoSWjDe7Bdhg2za24kwPAVZ7EK3qf9GvRCXYQT 5b_.w70WxaaleNsEYitEyK1j6o.Ae38745E5D.8NsHk0rDxt.CwGgSzHy2fXVuqmwv3fMjMJ8gEx GDzq5_mpCYtfeg7EvzaYFwNOqDKdMIPOefgfMv5mjXnRHxv8grhWvlTV43ZP7U3KEsFCExf6ksSD ZMvX.QTYDM0x4mGDqgHMB36jiMKboMBpMG01SsNWdZaX9lDIDuwrvz2xuFGGoxXgtH_WJnL6WDJC HJkwhEztzOVOQ3kkBfqv65IymFVj8e5tqCEAaY3GyxFlQzpLcuGgS.7YtEfOixIXKIG8yYF_pr72 NfgbF4l8h_NhqDfIadDjiAE4Tiv1lirQCx_1ydVN7iEE9vDqtoLVuVUkD5b7h.yS1aaj70g2nxWL lhu3a6RCtXd5kjX1jFMCGUNNj.FXzQm5FbCU_maKtI.2o9v4ogiEhGIpcC9dOI8g.Ke9mwREYyi9 yYda84tFS2JY0s4FmgsNOMf.aAOc8NB53.opFF_4NrYcgvlIeXAVoVDQq9XeRWiuLfjQ2qf8FIHx 4azly3ntQMvxOprrXeSvMpVam9l_zJm6xfyO9nzflpmtNiqdQddc4qxtj1Pp0x1rW6gFd04X_HR9 IR2VrvWiQpsmlbrhCeQ9JXHDJQ8eN8pHhJi8x2K5UCV6Z3PmIv25Jk80h49lVJizyY63_8Eamj.R cTFrf8Y9KSzzUfNiEL0qa82MNss_aWxdDQ8LkxavHur7d0MloatQEJ_JCGCxRb.qf8HGuW8Qf64i oMx0Yfvacm3uKtCdNKp.r__8mjRrOUAj29ybA_qNhqE7BgozqHbeLueQfnrocWRYALQZHd8jiK4_ gkczFzm01ONbmoVAwAWVAyyz0UjcojeHDl.00LZ1ArFLTI85mfIdeobYD5zg8Ry817PVg3aYCKfe Cu2C5dMT_xu48F9hSEH3MD6lQcxYEHk_GIt3E.8RjODNJ0LKGbqTftUpcgDYZ3KQIETPAZzDFFmh G0MT4OG0mB2MgSA-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic309.consmr.mail.ir2.yahoo.com with HTTP; Mon, 6 Jun 2022 17:36:02 +0000 Date: Mon, 6 Jun 2022 17:40:42 +0000 (UTC) From: Paolo Prete To: FFmpeg Development Discussions and Patches Message-ID: <580594123.12475702.1654537242853@mail.yahoo.com> MIME-Version: 1.0 References: <580594123.12475702.1654537242853.ref@mail.yahoo.com> X-Mailer: WebService/1.1.20225 YMailNorrin X-Content-Filtered-By: Mailman/MimeDel 2.1.29 Subject: [FFmpeg-devel] [PATCH] New API usage example (reading, converting, encoding and muxing an audio file) X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: fe7m4jXkFhYY Hello, From what I see, the doc/examples files can be still improved. More precisely, their main() is often split into functions with short names that hide important (sometime essential) details of what they're doing and they worsen the readability, by forcing the user to jump from chunks to chunks of the code. See for example: muxing.c (and the open_audio/video(), write_audio/video_frame()...). In addition: they are hard to adapt to practical cases without doing big modifications. Please consider to review/push the attached example:  convert_encode_mux_audio.c . It is deliberately written in a more "procedural" way, it should be much easier to read and it covers all the basic steps (reading from file, converting, encoding, muxing) of a common and practical pipeline made with ffMPEG. Hope it helps. P From 86db1c6dcd6f69028c9c25d03e6e19ef9fc2b331 Mon Sep 17 00:00:00 2001 From: paolo Date: Mon, 6 Jun 2022 15:34:05 +0200 Subject: [PATCH] Added a complete example - with clear, well readable and sequential code - for doing basic operations on a raw audio file. It improves the current state of the examples directory --- configure | 2 + doc/examples/Makefile | 47 ++-- doc/examples/Makefile.example | 1 + doc/examples/convert_encode_mux_audio.c | 351 ++++++++++++++++++++++++ 4 files changed, 378 insertions(+), 23 deletions(-) create mode 100644 doc/examples/convert_encode_mux_audio.c diff --git a/configure b/configure index 5a167613a4..775750aff0 100755 --- a/configure +++ b/configure @@ -1725,6 +1725,7 @@ COMPONENT_LIST=" EXAMPLE_LIST=" avio_list_dir_example avio_reading_example + convert_encode_mux_audio_example decode_audio_example decode_video_example demuxing_decoding_example @@ -3760,6 +3761,7 @@ yadif_videotoolbox_filter_deps="metal corevideo videotoolbox" # examples avio_list_dir_deps="avformat avutil" avio_reading_deps="avformat avcodec avutil" +convert_encode_mux_audio_example_deps="avcodec avformat avutil 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 81bfd34d5d..aed73e811c 100644 --- a/doc/examples/Makefile +++ b/doc/examples/Makefile @@ -1,26 +1,27 @@ -EXAMPLES-$(CONFIG_AVIO_LIST_DIR_EXAMPLE) += avio_list_dir -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_LIST_DIR_EXAMPLE) += avio_list_dir +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 a232d97f98..f2438caeb8 100644 --- a/doc/examples/Makefile.example +++ b/doc/examples/Makefile.example @@ -13,6 +13,7 @@ LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) $(LDLIBS) EXAMPLES= avio_list_dir \ avio_reading \ + convert_encode_mux_audio \ decode_audio \ decode_video \ demuxing_decoding \ diff --git a/doc/examples/convert_encode_mux_audio.c b/doc/examples/convert_encode_mux_audio.c new file mode 100644 index 0000000000..abde611bf6 --- /dev/null +++ b/doc/examples/convert_encode_mux_audio.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2019 Paolo Prete (paolopr976 at 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_AAC +#define ENCODER_BITRATE 64000 +#define INPUT_SAMPLE_FMT AV_SAMPLE_FMT_FLT +#define OUTPUT_SAMPLE_FMT AV_SAMPLE_FMT_FLTP +#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(const 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; + AVChannelLayout in_ch_layout; + AVChannelLayout out_ch_layout; + const AVCodec *audio_codec = NULL; + AVCodecContext *audio_encoder_ctx = NULL; + AVFrame *input_audio_frame = NULL, *converted_audio_frame = NULL; + SwrContext *audio_convert_context = NULL; + const 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; + } + av_channel_layout_default(&out_ch_layout, OUTPUT_CHANNELS); + 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->ch_layout = out_ch_layout; + 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; + } + av_channel_layout_default(&in_ch_layout, INPUT_CHANNELS); + input_audio_frame->nb_samples = audio_encoder_ctx->frame_size; + input_audio_frame->format = INPUT_SAMPLE_FMT; + input_audio_frame->sample_rate = SAMPLE_RATE; + input_audio_frame->ch_layout = in_ch_layout; + // 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()) + */ + swr_alloc_set_opts2(&audio_convert_context, + &out_ch_layout, + OUTPUT_SAMPLE_FMT, + SAMPLE_RATE, + &in_ch_layout, + 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->ch_layout = audio_encoder_ctx->ch_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 = converted_audio_frame->pts; + av_packet_rescale_ts(encoded_audio_packet, audio_encoder_ctx->time_base, + out_stream->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 = converted_audio_frame->nb_samples*(encoded_pkt_counter-1); + encoded_audio_packet->pts = encoded_audio_packet->dts; + av_packet_rescale_ts(encoded_audio_packet, audio_encoder_ctx->time_base, + out_stream->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; + +} -- 2.32.0