[Libav-user] New libav API usage axamples

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[Libav-user] New libav API usage axamples

Paolo Prete
Hello, 

during my last job's project I had to use very often the AV library for many purposes. Then, I created many snippets of code which are aligned to the ffmpeg's 3.2 version: they don't use deprecated functions (no warnings from compiler) and can be useful as API usage examples, considering that the current state of the doc/examples directory seems not good and a bit messy. All the snippets that I wrote are short, and they cover many audio+video tasks, from grabbing from audio/video devices to network streaming. If the FFMPEG developers think that they can be pushed in the doc/examples directory, I can spend time in re-organizing all the material and send it progressively to the FFMPEG project. For now, I send an example which converts a raw audio file to float-planar and encodes it to adts-aac. Please, give me some feedback and I'll go on in contributing to the project by sending other examples.



/*
 * Copyright (c) 2017 Paolo Prete ([hidden email])
 *
 * 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;
    
}












_______________________________________________
Libav-user mailing list
[hidden email]
http://ffmpeg.org/mailman/listinfo/libav-user

encode_raw_audio_file_to_aac.c (17K) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: New libav API usage axamples

Renaud BOBIN

Hello,

 

That’s a good idea !

I’m using ffmpeg to decode stream for a Network Camera, but the last time i use it, it was with the old library.

Example with the current library will be really helpful for all new users !

Thx for your work

 

Cordialement,

Renaud BOBIN
Project Engineer

 

Logo-miniSUBSEA TECH

Marine and Underwater Technologies

167 Plage de l'Estaque 13016 Marseille - France

Tel: +33 (0) 4 91 51 76 71

Web: www.subsea-tech.com

 

De : Libav-user [mailto:[hidden email]] De la part de Paolo Prete
Envoyé : lundi 27 mars 2017 02:05
À : [hidden email]
Objet : [Libav-user] New libav API usage axamples

 

Hello, 

 

during my last job's project I had to use very often the AV library for many purposes. Then, I created many snippets of code which are aligned to the ffmpeg's 3.2 version: they don't use deprecated functions (no warnings from compiler) and can be useful as API usage examples, considering that the current state of the doc/examples directory seems not good and a bit messy. All the snippets that I wrote are short, and they cover many audio+video tasks, from grabbing from audio/video devices to network streaming. If the FFMPEG developers think that they can be pushed in the doc/examples directory, I can spend time in re-organizing all the material and send it progressively to the FFMPEG project. For now, I send an example which converts a raw audio file to float-planar and encodes it to adts-aac. Please, give me some feedback and I'll go on in contributing to the project by sending other examples.

 

 

 

/*

 * Copyright (c) 2017 Paolo Prete ([hidden email])

 *

 * 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;

    

}

 

 

 

 

 

 

 

 

 

 

 


_______________________________________________
Libav-user mailing list
[hidden email]
http://ffmpeg.org/mailman/listinfo/libav-user
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: New libav API usage axamples

Gabor Alsecz
In reply to this post by Paolo Prete
Hello Paolo, Dear Libav Team,

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.

BR,
Gabor

On Mon, Mar 27, 2017 at 2:05 AM, Paolo Prete <[hidden email]> wrote:
Hello, 

during my last job's project I had to use very often the AV library for many purposes. Then, I created many snippets of code which are aligned to the ffmpeg's 3.2 version: they don't use deprecated functions (no warnings from compiler) and can be useful as API usage examples, considering that the current state of the doc/examples directory seems not good and a bit messy. All the snippets that I wrote are short, and they cover many audio+video tasks, from grabbing from audio/video devices to network streaming. If the FFMPEG developers think that they can be pushed in the doc/examples directory, I can spend time in re-organizing all the material and send it progressively to the FFMPEG project. For now, I send an example which converts a raw audio file to float-planar and encodes it to adts-aac. Please, give me some feedback and I'll go on in contributing to the project by sending other examples.



/*
 * Copyright (c) 2017 Paolo Prete ([hidden email])
 *
 * 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;
    
}












_______________________________________________
Libav-user mailing list
[hidden email]
http://ffmpeg.org/mailman/listinfo/libav-user



_______________________________________________
Libav-user mailing list
[hidden email]
http://ffmpeg.org/mailman/listinfo/libav-user
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: New libav API usage axamples

Carl Eugen Hoyos-2
2017-03-27 9:11 GMT+02:00 Gabor Alsecz <[hidden email]>:

> 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
[hidden email]
http://ffmpeg.org/mailman/listinfo/libav-user
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: New libav API usage axamples

Paolo Prete
Il Lunedì 27 Marzo 2017 10:05, Carl Eugen Hoyos <[hidden email]> ha scritto:




2017-03-27 9:11 GMT+02:00 Gabor Alsecz <[hidden email]>:

> 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
[hidden email]
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.





_______________________________________________
Libav-user mailing list
[hidden email]
http://ffmpeg.org/mailman/listinfo/libav-user

0001-Makefile-changed-in-order-to-include-a-new-API-usage.patch (1K) Download Attachment
0001-new-API-usage-example.patch (18K) Download Attachment
Loading...