[Libav-user] New libav API usage axamples

Gabor Alsecz alseczg at gmail.com
Mon Mar 27 10:11:13 EEST 2017


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 <
p4olo_prete-at-yahoo.it at ffmpeg.org> 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 (p4olo_prete at 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;
>
> }
>
>
>
>
>
>
>
>
>
>
>
>
> _______________________________________________
> Libav-user mailing list
> Libav-user at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/libav-user
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20170327/a3449e23/attachment.html>


More information about the Libav-user mailing list