Il Lunedì 27 Marzo 2017 10:05, Carl Eugen Hoyos <ceffm...@gmail.com> ha scritto:


 

 2017-03-27 9:11 GMT+02:00 Gabor Alsecz <alse...@gmail.com>:

> Thanks for the code snippet you have pasted here. Many of us
> struggling here because lack of samples even based on the latest API.
> I just can confirm to the Libav team we really would need new API
> examples and please try to figure out the way how Paolo can share
> his snippets commonly.

(Speaking for FFmpeg, not any forks)
If the snippets provide advantages over the code in doc/examples,
please send your patch (against current FFmpeg git head) made
with git format-patch to the FFmpeg development mailing list.
This is also where the feedback comes from.

Carl Eugen
_______________________________________________
Libav-user mailing list
libav-u...@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/libav-user





Hello,
The snippet I posted could provide these advantages:
1) it can easily be adapted to any audio input source (i.e: a live source)
2) it is short and written in a strict procedural way, without using any 
function which splits the code with the result of forcing the reader/user to 
jump from a line to another one in order to understand in details what's 
happening.
3) all the tasks are separated and all of them are exposed to the user without 
using functions which hide internal tasks/containers; i.e: muxed data is stored 
in memory and exposed through a callback function. Therefore, the user can pick 
specific portions of the code (input raw frame, resampled frame, encoded packet 
and muxed data) and adapt them to his needings.
4) it can be easily adapted to other audio codecs: I used the aac one, in the 
example, because it requires a container (adts), then it improves the basic 
knowledge of the API; but the user can adapt the snippet to mp2 codec, for 
example, by simply removing the container part, and he can directly write to 
file the encoded packets.
5) The cleanup stuff is divided into steps.

This message is cross-posted to the ffmpeg-devel mailing list and includes the 
previous snippet in form of patches in git format-patch (Makefile and snippet 
files). If it will be accepted, I can provide the next example, which covers 
h264 encoding, muxing and streaming.



   
From 9e5f3d83bf42b987386a0566a8b4554315e336e8 Mon Sep 17 00:00:00 2001
From: Paolo Prete <p4olo_pr...@yahoo.it>
Date: Mon, 27 Mar 2017 23:09:07 +0200
Subject: [PATCH] Makefile changed in order to include a new API usage example
 (encode_raw_audio_file_to_aac.c)

---
 doc/examples/Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/examples/Makefile b/doc/examples/Makefile
index af38159..f316bfb 100644
--- a/doc/examples/Makefile
+++ b/doc/examples/Makefile
@@ -15,6 +15,7 @@ EXAMPLES=       avio_dir_cmd                       \
                 avio_reading                       \
                 decoding_encoding                  \
                 demuxing_decoding                  \
+		encode_raw_audio_file_to_aac       \
                 extract_mvs                        \
                 filtering_video                    \
                 filtering_audio                    \
-- 
2.9.3

From 3d7afbccf35186890b5b8151342cb17dfc9d38e4 Mon Sep 17 00:00:00 2001
From: Paolo Prete <p4olo_pr...@yahoo.it>
Date: Mon, 27 Mar 2017 23:07:12 +0200
Subject: [PATCH] new API usage example

---
 doc/examples/encode_raw_audio_file_to_aac.c | 326 ++++++++++++++++++++++++++++
 1 file changed, 326 insertions(+)
 create mode 100644 doc/examples/encode_raw_audio_file_to_aac.c

diff --git a/doc/examples/encode_raw_audio_file_to_aac.c b/doc/examples/encode_raw_audio_file_to_aac.c
new file mode 100644
index 0000000..045df33
--- /dev/null
+++ b/doc/examples/encode_raw_audio_file_to_aac.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2017 Paolo Prete (p4olo_pr...@yahoo.it)
+ *
+ * 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 adts-aac encoding raw audio files. 
+ * This example reads a raw audio input file, converts it to float-planar format, performs aac encoding and puts the encoded frames into an ADTS container. The encoded stream is written to 
+ * a file named "out.aac"
+ * The raw input audio file can be created with: ffmpeg -i some_audio_file -f f32le -acodec pcm_f32le -ac 2 -ar 16000 raw_audio_file.raw
+ * 
+ * @example encode_raw_audio_file_to_aac.c
+ */
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavutil/timestamp.h>
+#include <libswresample/swresample.h>
+
+
+#define ENCODER_BITRATE 64000
+#define SAMPLE_RATE 16000
+#define INPUT_SAMPLE_FMT AV_SAMPLE_FMT_FLT
+#define CHANNELS 2
+
+
+static char *const get_error_text(const int error)
+{
+    static char error_buffer[255];
+    av_strerror(error, error_buffer, sizeof(error_buffer));
+    return error_buffer;
+}
+
+
+static int write_adts_muxed_data (void *opaque, uint8_t *adts_data, int size)
+{
+    FILE *encoded_audio_file = (FILE *)opaque;
+    fwrite(adts_data, 1, size, encoded_audio_file); //(f)
+    return size;
+}
+
+
+int main(int argc, char **argv)
+{
+    
+    
+    if (argc != 2) {
+        av_log(NULL, AV_LOG_ERROR, "Usage: %s <raw audio input file (CHANNELS, INPUT_SAMPLE_FMT, SAMPLE_RATE)>\n", argv[0]);
+        return 1;
+    }    
+    
+    
+    int ret_val = 0;
+    int cleanup_step = 1;    
+    
+    
+    
+    FILE *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;
+    }
+    
+    FILE *encoded_audio_file = fopen("out.aac", "wb");  
+    if(!encoded_audio_file){
+        av_log(NULL, AV_LOG_ERROR, "Could not open output audio file\n");
+        ret_val = AVERROR_EXIT;
+        goto cleanup;
+    }     
+    ++cleanup_step;    
+
+    
+    
+    av_register_all();
+
+    
+    
+    //
+    // Allocate the encoder's context and open the encoder
+    //
+    AVCodec *audio_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
+    if(!audio_codec){
+        av_log(NULL, AV_LOG_ERROR, "Could not find aac codec\n");
+        ret_val = AVERROR_EXIT;
+        goto cleanup;
+    }
+    AVCodecContext *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 cleanup;
+    }    
+    ++cleanup_step;
+    audio_encoder_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+    audio_encoder_ctx->bit_rate = ENCODER_BITRATE;
+    audio_encoder_ctx->sample_rate = SAMPLE_RATE; // You can use any other sample rate provided by the input file on condition that it is supported by the codec (use AVCodec::supported_samplerates for listing supported sample rates)
+    audio_encoder_ctx->channels = CHANNELS;
+    audio_encoder_ctx->channel_layout = av_get_default_channel_layout(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", get_error_text(ret_val));
+        goto cleanup;
+    }
+    ++cleanup_step;
+    
+    
+    //
+    // Allocate an AVFrame which will be filled with the input file's data. 
+    //
+    AVFrame *input_audio_frame;
+    if (!(input_audio_frame = av_frame_alloc())) {
+        av_log(NULL, AV_LOG_ERROR, "Could not allocate input frame\n");
+        ret_val = AVERROR(ENOMEM);
+        goto cleanup;
+    }    
+    input_audio_frame->nb_samples     = audio_encoder_ctx->frame_size;
+    input_audio_frame->format         = INPUT_SAMPLE_FMT;
+    input_audio_frame->channels       = CHANNELS;
+    input_audio_frame->sample_rate    = SAMPLE_RATE;
+    input_audio_frame->channel_layout = av_get_default_channel_layout(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", get_error_text(ret_val));
+        ret_val = AVERROR(ENOMEM);
+        goto cleanup;
+    }    
+    
+    
+    
+    //
+    // Input data must be converted to float-planar format, which is the format required by the AAC 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())
+    //
+    SwrContext *audio_convert_context = swr_alloc_set_opts(NULL, av_get_default_channel_layout(CHANNELS), AV_SAMPLE_FMT_FLTP, SAMPLE_RATE, av_get_default_channel_layout(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 cleanup;
+    }    
+    ++cleanup_step;
+    AVFrame *converted_audio_frame;
+    if (!(converted_audio_frame = av_frame_alloc())) {
+        av_log(NULL, AV_LOG_ERROR, "Could not allocate resampled frame\n");
+        ret_val = AVERROR(ENOMEM);
+        goto cleanup;
+    }     
+    ++cleanup_step;
+    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", get_error_text(ret_val));
+        goto cleanup;
+    }    
+    
+    
+    
+    //
+    // Create the ADTS container for the encoded frames
+    //
+    AVOutputFormat *adts_container = av_guess_format("adts", NULL, NULL);
+    if (!adts_container) {
+        av_log(NULL, AV_LOG_ERROR, "Could not find adts output format\n");       
+        ret_val = AVERROR_EXIT;
+        goto cleanup;
+    }     
+    AVFormatContext *adts_container_ctx;
+    if ((ret_val = avformat_alloc_output_context2(&adts_container_ctx, adts_container, "", NULL)) < 0){
+        av_log(NULL, AV_LOG_ERROR, "Could not create output context (error '%s')\n", get_error_text(ret_val));
+        goto cleanup;
+    }
+    ++cleanup_step;
+    size_t adts_container_buffer_size = 4096;
+    uint8_t *adts_container_buffer;
+    if(!(adts_container_buffer = (uint8_t* )av_malloc(adts_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 cleanup; 
+    }
+    ++cleanup_step;
+    // Create an I/O context for the adts container with a write callback (write_adts_muxed_data()), so that muxed data will be accessed through this function.
+    AVIOContext *adts_avio_ctx;
+    if (!(adts_avio_ctx = avio_alloc_context(adts_container_buffer, adts_container_buffer_size, 1, encoded_audio_file, NULL , &write_adts_muxed_data, NULL))) {
+        av_log(NULL, AV_LOG_ERROR, "Could not create I/O output context\n");
+        ret_val = AVERROR_EXIT;
+        goto cleanup;
+    }
+    ++cleanup_step;
+    // Link the container's context to the previous I/O context
+    adts_container_ctx->pb = adts_avio_ctx;
+    AVStream *adts_stream;
+    if (!(adts_stream = avformat_new_stream(adts_container_ctx, NULL))) {
+        av_log(NULL, AV_LOG_ERROR, "Could not create new stream\n");       
+        ret_val = AVERROR(ENOMEM);
+        goto cleanup;        
+    }    
+    adts_stream->id = adts_container_ctx->nb_streams-1;
+    // Copy the encoder's parameters 
+    avcodec_parameters_from_context(adts_stream->codecpar, audio_encoder_ctx);    
+    // Allocate the stream private data and write the stream header
+    if(avformat_write_header(adts_container_ctx, NULL) < 0){
+        av_log(NULL, AV_LOG_ERROR, "avformat_write_header() error\n");
+        ret_val = AVERROR_EXIT;
+        goto cleanup;
+    }        
+    ++cleanup_step;
+    
+    
+    
+    //
+    // Fill the input frame's data buffer with input file data (a), 
+    // Convert the input frame to float-planar format (b), 
+    // Send the converted frame to the encoder (c), 
+    // Get the encoded packet (d),
+    // Send the encoded packet to the adts muxer (e). 
+    // Muxed data is caught in write_adts_muxed_data() callback and it is written to the output audio file ( (f) : see above)
+    //
+    AVPacket encoded_audio_packet;
+    av_init_packet(&encoded_audio_packet);
+    int encoded_pkt_counter = 1;
+    while(1) {
+        int audio_bytes_to_encode = fread(input_audio_frame->data[0], 1, input_audio_frame->linesize[0], input_audio_file); //(a)
+        swr_convert_frame(audio_convert_context, converted_audio_frame, (const AVFrame *)input_audio_frame); //(b)
+        if(audio_bytes_to_encode != input_audio_frame->linesize[0]){            
+            break;
+        }
+        else {
+            // Do encode
+            ret_val = avcodec_send_frame(audio_encoder_ctx, converted_audio_frame);  //(c)
+            if(ret_val == 0) 
+                ret_val = avcodec_receive_packet(audio_encoder_ctx, &encoded_audio_packet); //(d)
+            else{
+                av_log(NULL, AV_LOG_ERROR, "Error encoding frame (error '%s')\n", get_error_text(ret_val));
+                goto cleanup;
+            }
+            
+            if(ret_val == 0){                
+                int64_t pts = converted_audio_frame->nb_samples*(encoded_pkt_counter-1);
+                encoded_audio_packet.pts = encoded_audio_packet.dts = pts;           
+                if((ret_val == av_write_frame(adts_container_ctx, &encoded_audio_packet)) < 0){ //(e)
+                    av_log(NULL, AV_LOG_ERROR, "Error calling av_write_frame() (error '%s')\n", get_error_text(ret_val));
+                    goto cleanup;
+                }
+                else{
+                    av_log(NULL, AV_LOG_INFO, "Encoded AAC packet %d, size=%d, pts_time=%s\n", encoded_pkt_counter, encoded_audio_packet.size, av_ts2timestr(encoded_audio_packet.pts, &audio_encoder_ctx->time_base));
+                    ++encoded_pkt_counter;
+                }
+            }
+        }            
+    }
+    // Flush delayed packets
+    int still_pkts_to_flush = 1;
+    int delayed_pkt_counter = 1;    
+    while(still_pkts_to_flush){
+        int ret = avcodec_send_frame(audio_encoder_ctx, NULL);
+        if(ret != 0)
+            still_pkts_to_flush = 0;
+        ret = avcodec_receive_packet(audio_encoder_ctx, &encoded_audio_packet);
+        if(ret == 0){
+            int64_t pts = converted_audio_frame->nb_samples*(encoded_pkt_counter-1);
+            encoded_audio_packet.pts = encoded_audio_packet.dts = pts; 
+            av_write_frame(adts_container_ctx, &encoded_audio_packet);
+            av_log(NULL, AV_LOG_INFO, "Flushed encoded AAC delayed packet %d, size=%d, pts_time=%s\n", delayed_pkt_counter, encoded_audio_packet.size, av_ts2timestr(encoded_audio_packet.pts, &audio_encoder_ctx->time_base));
+            ++delayed_pkt_counter;
+            ++encoded_pkt_counter;
+        }        
+    }
+
+    
+    av_write_trailer(adts_container_ctx);  
+
+    
+    
+    
+cleanup:    
+
+
+    if(cleanup_step > 0)
+        fclose(input_audio_file);
+    if(cleanup_step > 1)
+        fclose(encoded_audio_file); 
+    if(cleanup_step > 2)    
+        avcodec_free_context(&audio_encoder_ctx);
+    if(cleanup_step > 3)     
+        av_frame_free(&input_audio_frame);
+    if(cleanup_step > 4)     
+        swr_free(&audio_convert_context);   
+    if(cleanup_step > 5)     
+        av_frame_free(&converted_audio_frame);
+    if(cleanup_step > 6)    
+        avformat_free_context(adts_container_ctx);
+    if(cleanup_step > 7)    
+        av_free(adts_container_buffer);
+    if(cleanup_step > 8)    
+        av_free(adts_avio_ctx);  
+    if(cleanup_step > 9)    
+        av_packet_unref(&encoded_audio_packet);    
+    
+    
+    return ret_val;
+    
+}
+
+
+
-- 
2.9.3

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to