examples: Fixed and extended Doxygen documentation
Added parameter descriptions for all functions and converted in-function comments into regular (non-Doxygen) comments. Signed-off-by: Vittorio Giovara <vittorio.giovara@gmail.com>
This commit is contained in:
		
							parent
							
								
									efddf2c09a
								
							
						
					
					
						commit
						b200a2c8da
					
				| @ -1,4 +1,6 @@ | ||||
| /*
 | ||||
|  * Copyright (c) 2013-2017 Andreas Unterweger | ||||
|  * | ||||
|  * This file is part of Libav. | ||||
|  * | ||||
|  * Libav is free software; you can redistribute it and/or | ||||
| @ -18,10 +20,11 @@ | ||||
| 
 | ||||
| /**
 | ||||
|  * @file | ||||
|  * simple audio converter | ||||
|  * Simple audio converter | ||||
|  * | ||||
|  * @example transcode_aac.c | ||||
|  * Convert an input audio file to AAC in an MP4 container using Libav. | ||||
|  * Formats other than MP4 are supported based on the output file extension. | ||||
|  * @author Andreas Unterweger (dustsigns@gmail.com) | ||||
|  */ | ||||
| 
 | ||||
| @ -39,9 +42,9 @@ | ||||
| 
 | ||||
| #include "libavresample/avresample.h" | ||||
| 
 | ||||
| /** The output bit rate in kbit/s */ | ||||
| /* The output bit rate in bit/s */ | ||||
| #define OUTPUT_BIT_RATE 96000 | ||||
| /** The number of output channels */ | ||||
| /* The number of output channels */ | ||||
| #define OUTPUT_CHANNELS 2 | ||||
| 
 | ||||
| /**
 | ||||
| @ -56,7 +59,13 @@ static char *get_error_text(const int error) | ||||
|     return error_buffer; | ||||
| } | ||||
| 
 | ||||
| /** Open an input file and the required decoder. */ | ||||
| /**
 | ||||
|  * Open an input file and the required decoder. | ||||
|  * @param      filename             File to be opened | ||||
|  * @param[out] input_format_context Format context of opened file | ||||
|  * @param[out] input_codec_context  Codec context of opened file | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int open_input_file(const char *filename, | ||||
|                            AVFormatContext **input_format_context, | ||||
|                            AVCodecContext **input_codec_context) | ||||
| @ -65,7 +74,7 @@ static int open_input_file(const char *filename, | ||||
|     AVCodec *input_codec; | ||||
|     int error; | ||||
| 
 | ||||
|     /** Open the input file to read from it. */ | ||||
|     /* Open the input file to read from it. */ | ||||
|     if ((error = avformat_open_input(input_format_context, filename, NULL, | ||||
|                                      NULL)) < 0) { | ||||
|         fprintf(stderr, "Could not open input file '%s' (error '%s')\n", | ||||
| @ -74,7 +83,7 @@ static int open_input_file(const char *filename, | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /** Get information on the input file (number of streams etc.). */ | ||||
|     /* Get information on the input file (number of streams etc.). */ | ||||
|     if ((error = avformat_find_stream_info(*input_format_context, NULL)) < 0) { | ||||
|         fprintf(stderr, "Could not open find stream info (error '%s')\n", | ||||
|                 get_error_text(error)); | ||||
| @ -82,7 +91,7 @@ static int open_input_file(const char *filename, | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /** Make sure that there is only one stream in the input file. */ | ||||
|     /* Make sure that there is only one stream in the input file. */ | ||||
|     if ((*input_format_context)->nb_streams != 1) { | ||||
|         fprintf(stderr, "Expected one audio input stream, but found %d\n", | ||||
|                 (*input_format_context)->nb_streams); | ||||
| @ -90,14 +99,14 @@ static int open_input_file(const char *filename, | ||||
|         return AVERROR_EXIT; | ||||
|     } | ||||
| 
 | ||||
|     /** Find a decoder for the audio stream. */ | ||||
|     /* Find a decoder for the audio stream. */ | ||||
|     if (!(input_codec = avcodec_find_decoder((*input_format_context)->streams[0]->codecpar->codec_id))) { | ||||
|         fprintf(stderr, "Could not find input codec\n"); | ||||
|         avformat_close_input(input_format_context); | ||||
|         return AVERROR_EXIT; | ||||
|     } | ||||
| 
 | ||||
|     /** allocate a new decoding context */ | ||||
|     /* Allocate a new decoding context. */ | ||||
|     avctx = avcodec_alloc_context3(input_codec); | ||||
|     if (!avctx) { | ||||
|         fprintf(stderr, "Could not allocate a decoding context\n"); | ||||
| @ -105,7 +114,7 @@ static int open_input_file(const char *filename, | ||||
|         return AVERROR(ENOMEM); | ||||
|     } | ||||
| 
 | ||||
|     /** initialize the stream parameters with demuxer information */ | ||||
|     /* Initialize the stream parameters with demuxer information. */ | ||||
|     error = avcodec_parameters_to_context(avctx, (*input_format_context)->streams[0]->codecpar); | ||||
|     if (error < 0) { | ||||
|         avformat_close_input(input_format_context); | ||||
| @ -113,7 +122,7 @@ static int open_input_file(const char *filename, | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /** Open the decoder for the audio stream to use it later. */ | ||||
|     /* Open the decoder for the audio stream to use it later. */ | ||||
|     if ((error = avcodec_open2(avctx, input_codec, NULL)) < 0) { | ||||
|         fprintf(stderr, "Could not open input codec (error '%s')\n", | ||||
|                 get_error_text(error)); | ||||
| @ -122,7 +131,7 @@ static int open_input_file(const char *filename, | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /** Save the decoder context for easier access later. */ | ||||
|     /* Save the decoder context for easier access later. */ | ||||
|     *input_codec_context = avctx; | ||||
| 
 | ||||
|     return 0; | ||||
| @ -132,6 +141,11 @@ static int open_input_file(const char *filename, | ||||
|  * Open an output file and the required encoder. | ||||
|  * Also set some basic encoder parameters. | ||||
|  * Some of these parameters are based on the input file's parameters. | ||||
|  * @param      filename              File to be opened | ||||
|  * @param      input_codec_context   Codec context of input file | ||||
|  * @param[out] output_format_context Format context of output file | ||||
|  * @param[out] output_codec_context  Codec context of output file | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int open_output_file(const char *filename, | ||||
|                             AVCodecContext *input_codec_context, | ||||
| @ -144,7 +158,7 @@ static int open_output_file(const char *filename, | ||||
|     AVCodec *output_codec          = NULL; | ||||
|     int error; | ||||
| 
 | ||||
|     /** Open the output file to write to it. */ | ||||
|     /* Open the output file to write to it. */ | ||||
|     if ((error = avio_open(&output_io_context, filename, | ||||
|                            AVIO_FLAG_WRITE)) < 0) { | ||||
|         fprintf(stderr, "Could not open output file '%s' (error '%s')\n", | ||||
| @ -152,16 +166,16 @@ static int open_output_file(const char *filename, | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /** Create a new format context for the output container format. */ | ||||
|     /* Create a new format context for the output container format. */ | ||||
|     if (!(*output_format_context = avformat_alloc_context())) { | ||||
|         fprintf(stderr, "Could not allocate output format context\n"); | ||||
|         return AVERROR(ENOMEM); | ||||
|     } | ||||
| 
 | ||||
|     /** Associate the output file (pointer) with the container format context. */ | ||||
|     /* Associate the output file (pointer) with the container format context. */ | ||||
|     (*output_format_context)->pb = output_io_context; | ||||
| 
 | ||||
|     /** Guess the desired container format based on the file extension. */ | ||||
|     /* Guess the desired container format based on the file extension. */ | ||||
|     if (!((*output_format_context)->oformat = av_guess_format(NULL, filename, | ||||
|                                                               NULL))) { | ||||
|         fprintf(stderr, "Could not find output file format\n"); | ||||
| @ -171,13 +185,13 @@ static int open_output_file(const char *filename, | ||||
|     av_strlcpy((*output_format_context)->filename, filename, | ||||
|                sizeof((*output_format_context)->filename)); | ||||
| 
 | ||||
|     /** Find the encoder to be used by its name. */ | ||||
|     /* Find the encoder to be used by its name. */ | ||||
|     if (!(output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC))) { | ||||
|         fprintf(stderr, "Could not find an AAC encoder.\n"); | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     /** Create a new audio stream in the output file container. */ | ||||
|     /* Create a new audio stream in the output file container. */ | ||||
|     if (!(stream = avformat_new_stream(*output_format_context, NULL))) { | ||||
|         fprintf(stderr, "Could not create new stream\n"); | ||||
|         error = AVERROR(ENOMEM); | ||||
| @ -191,31 +205,27 @@ static int open_output_file(const char *filename, | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Set the basic encoder parameters. | ||||
|      * The input file's sample rate is used to avoid a sample rate conversion. | ||||
|      */ | ||||
|     /* Set the basic encoder parameters.
 | ||||
|      * The input file's sample rate is used to avoid a sample rate conversion. */ | ||||
|     avctx->channels       = OUTPUT_CHANNELS; | ||||
|     avctx->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS); | ||||
|     avctx->sample_rate    = input_codec_context->sample_rate; | ||||
|     avctx->sample_fmt     = output_codec->sample_fmts[0]; | ||||
|     avctx->bit_rate       = OUTPUT_BIT_RATE; | ||||
| 
 | ||||
|     /** Allow the use of the experimental AAC encoder */ | ||||
|     /* Allow the use of the experimental AAC encoder. */ | ||||
|     avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; | ||||
| 
 | ||||
|     /** Set the sample rate for the container. */ | ||||
|     /* Set the sample rate for the container. */ | ||||
|     stream->time_base.den = input_codec_context->sample_rate; | ||||
|     stream->time_base.num = 1; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Some container formats (like MP4) require global headers to be present | ||||
|      * Mark the encoder so that it behaves accordingly. | ||||
|      */ | ||||
|     /* Some container formats (like MP4) require global headers to be present.
 | ||||
|      * Mark the encoder so that it behaves accordingly. */ | ||||
|     if ((*output_format_context)->oformat->flags & AVFMT_GLOBALHEADER) | ||||
|         avctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | ||||
| 
 | ||||
|     /** Open the encoder for the audio stream to use it later. */ | ||||
|     /* Open the encoder for the audio stream to use it later. */ | ||||
|     if ((error = avcodec_open2(avctx, output_codec, NULL)) < 0) { | ||||
|         fprintf(stderr, "Could not open output codec (error '%s')\n", | ||||
|                 get_error_text(error)); | ||||
| @ -228,7 +238,7 @@ static int open_output_file(const char *filename, | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     /** Save the encoder context for easier access later. */ | ||||
|     /* Save the encoder context for easier access later. */ | ||||
|     *output_codec_context = avctx; | ||||
| 
 | ||||
|     return 0; | ||||
| @ -241,16 +251,23 @@ cleanup: | ||||
|     return error < 0 ? error : AVERROR_EXIT; | ||||
| } | ||||
| 
 | ||||
| /** Initialize one data packet for reading or writing. */ | ||||
| /**
 | ||||
|  * Initialize one data packet for reading or writing. | ||||
|  * @param packet Packet to be initialized | ||||
|  */ | ||||
| static void init_packet(AVPacket *packet) | ||||
| { | ||||
|     av_init_packet(packet); | ||||
|     /** Set the packet data and size so that it is recognized as being empty. */ | ||||
|     /* Set the packet data and size so that it is recognized as being empty. */ | ||||
|     packet->data = NULL; | ||||
|     packet->size = 0; | ||||
| } | ||||
| 
 | ||||
| /** Initialize one audio frame for reading from the input file */ | ||||
| /**
 | ||||
|  * Initialize one audio frame for reading from the input file. | ||||
|  * @param[out] frame Frame to be initialized | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int init_input_frame(AVFrame **frame) | ||||
| { | ||||
|     if (!(*frame = av_frame_alloc())) { | ||||
| @ -264,27 +281,28 @@ static int init_input_frame(AVFrame **frame) | ||||
|  * Initialize the audio resampler based on the input and output codec settings. | ||||
|  * If the input and output sample formats differ, a conversion is required | ||||
|  * libavresample takes care of this, but requires initialization. | ||||
|  * @param      input_codec_context  Codec context of the input file | ||||
|  * @param      output_codec_context Codec context of the output file | ||||
|  * @param[out] resample_context     Resample context for the required conversion | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int init_resampler(AVCodecContext *input_codec_context, | ||||
|                           AVCodecContext *output_codec_context, | ||||
|                           AVAudioResampleContext **resample_context) | ||||
| { | ||||
|     /**
 | ||||
|      * Only initialize the resampler if it is necessary, i.e., | ||||
|      * if and only if the sample formats differ. | ||||
|      */ | ||||
|     /* Only initialize the resampler if it is necessary, i.e.,
 | ||||
|      * if and only if the sample formats differ. */ | ||||
|     if (input_codec_context->sample_fmt != output_codec_context->sample_fmt || | ||||
|         input_codec_context->channels != output_codec_context->channels) { | ||||
|         int error; | ||||
| 
 | ||||
|         /** Create a resampler context for the conversion. */ | ||||
|         /* Create a resampler context for the conversion. */ | ||||
|         if (!(*resample_context = avresample_alloc_context())) { | ||||
|             fprintf(stderr, "Could not allocate resample context\n"); | ||||
|             return AVERROR(ENOMEM); | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|          * Set the conversion parameters. | ||||
|         /* Set the conversion parameters.
 | ||||
|          * Default channel layouts based on the number of channels | ||||
|          * are assumed for simplicity (they are sometimes not detected | ||||
|          * properly by the demuxer and/or decoder). | ||||
| @ -302,7 +320,7 @@ static int init_resampler(AVCodecContext *input_codec_context, | ||||
|         av_opt_set_int(*resample_context, "out_sample_fmt", | ||||
|                        output_codec_context->sample_fmt, 0); | ||||
| 
 | ||||
|         /** Open the resampler with the specified parameters. */ | ||||
|         /* Open the resampler with the specified parameters. */ | ||||
|         if ((error = avresample_open(*resample_context)) < 0) { | ||||
|             fprintf(stderr, "Could not open resample context\n"); | ||||
|             avresample_free(resample_context); | ||||
| @ -312,10 +330,15 @@ static int init_resampler(AVCodecContext *input_codec_context, | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /** Initialize a FIFO buffer for the audio samples to be encoded. */ | ||||
| /**
 | ||||
|  * Initialize a FIFO buffer for the audio samples to be encoded. | ||||
|  * @param[out] fifo                 Sample buffer | ||||
|  * @param      output_codec_context Codec context of the output file | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context) | ||||
| { | ||||
|     /** Create the FIFO buffer based on the specified output sample format. */ | ||||
|     /* Create the FIFO buffer based on the specified output sample format. */ | ||||
|     if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt, | ||||
|                                       output_codec_context->channels, 1))) { | ||||
|         fprintf(stderr, "Could not allocate FIFO\n"); | ||||
| @ -324,7 +347,11 @@ static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context) | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /** Write the header of the output file container. */ | ||||
| /**
 | ||||
|  * Write the header of the output file container. | ||||
|  * @param output_format_context Format context of the output file | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int write_output_file_header(AVFormatContext *output_format_context) | ||||
| { | ||||
|     int error; | ||||
| @ -336,20 +363,32 @@ static int write_output_file_header(AVFormatContext *output_format_context) | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /** Decode one audio frame from the input file. */ | ||||
| /**
 | ||||
|  * Decode one audio frame from the input file. | ||||
|  * @param      frame                Audio frame to be decoded | ||||
|  * @param      input_format_context Format context of the input file | ||||
|  * @param      input_codec_context  Codec context of the input file | ||||
|  * @param[out] data_present         Indicates whether data has been decoded | ||||
|  * @param[out] finished             Indicates whether the end of file has | ||||
|  *                                  been reached and all data has been | ||||
|  *                                  decoded. If this flag is false, there | ||||
|  *                                  is more data to be decoded, i.e., this | ||||
|  *                                  function has to be called again. | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int decode_audio_frame(AVFrame *frame, | ||||
|                               AVFormatContext *input_format_context, | ||||
|                               AVCodecContext *input_codec_context, | ||||
|                               int *data_present, int *finished) | ||||
| { | ||||
|     /** Packet used for temporary storage. */ | ||||
|     /* Packet used for temporary storage. */ | ||||
|     AVPacket input_packet; | ||||
|     int error; | ||||
|     init_packet(&input_packet); | ||||
| 
 | ||||
|     /** Read one audio frame from the input file into a temporary packet. */ | ||||
|     /* Read one audio frame from the input file into a temporary packet. */ | ||||
|     if ((error = av_read_frame(input_format_context, &input_packet)) < 0) { | ||||
|         /** If we are the the end of the file, flush the decoder below. */ | ||||
|         /* If we are the the end of the file, flush the decoder below. */ | ||||
|         if (error == AVERROR_EOF) | ||||
|             *finished = 1; | ||||
|         else { | ||||
| @ -359,12 +398,10 @@ static int decode_audio_frame(AVFrame *frame, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Decode the audio frame stored in the temporary packet. | ||||
|     /* Decode the audio frame stored in the temporary packet.
 | ||||
|      * The input audio stream decoder is used to do this. | ||||
|      * If we are at the end of the file, pass an empty packet to the decoder | ||||
|      * to flush it. | ||||
|      */ | ||||
|      * to flush it. */ | ||||
|     if ((error = avcodec_decode_audio4(input_codec_context, frame, | ||||
|                                        data_present, &input_packet)) < 0) { | ||||
|         fprintf(stderr, "Could not decode frame (error '%s')\n", | ||||
| @ -373,10 +410,8 @@ static int decode_audio_frame(AVFrame *frame, | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * If the decoder has not been flushed completely, we are not finished, | ||||
|      * so that this function has to be called again. | ||||
|      */ | ||||
|     /* If the decoder has not been flushed completely, we are not finished,
 | ||||
|      * so that this function has to be called again. */ | ||||
|     if (*finished && *data_present) | ||||
|         *finished = 0; | ||||
|     av_packet_unref(&input_packet); | ||||
| @ -387,6 +422,13 @@ static int decode_audio_frame(AVFrame *frame, | ||||
|  * Initialize a temporary storage for the specified number of audio samples. | ||||
|  * The conversion requires temporary storage due to the different format. | ||||
|  * The number of audio samples to be allocated is specified in frame_size. | ||||
|  * @param[out] converted_input_samples Array of converted samples. The | ||||
|  *                                     dimensions are reference, channel | ||||
|  *                                     (for multi-channel audio), sample. | ||||
|  * @param      output_codec_context    Codec context of the output file | ||||
|  * @param      frame_size              Number of samples to be converted in | ||||
|  *                                     each round | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int init_converted_samples(uint8_t ***converted_input_samples, | ||||
|                                   AVCodecContext *output_codec_context, | ||||
| @ -394,8 +436,7 @@ static int init_converted_samples(uint8_t ***converted_input_samples, | ||||
| { | ||||
|     int error; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Allocate as many pointers as there are audio channels. | ||||
|     /* Allocate as many pointers as there are audio channels.
 | ||||
|      * Each pointer will later point to the audio samples of the corresponding | ||||
|      * channels (although it may be NULL for interleaved formats). | ||||
|      */ | ||||
| @ -405,10 +446,8 @@ static int init_converted_samples(uint8_t ***converted_input_samples, | ||||
|         return AVERROR(ENOMEM); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Allocate memory for the samples of all channels in one consecutive | ||||
|      * block for convenience. | ||||
|      */ | ||||
|     /* Allocate memory for the samples of all channels in one consecutive
 | ||||
|      * block for convenience. */ | ||||
|     if ((error = av_samples_alloc(*converted_input_samples, NULL, | ||||
|                                   output_codec_context->channels, | ||||
|                                   frame_size, | ||||
| @ -425,8 +464,15 @@ static int init_converted_samples(uint8_t ***converted_input_samples, | ||||
| 
 | ||||
| /**
 | ||||
|  * Convert the input audio samples into the output sample format. | ||||
|  * The conversion happens on a per-frame basis, the size of which is specified | ||||
|  * by frame_size. | ||||
|  * The conversion happens on a per-frame basis, the size of which is | ||||
|  * specified by frame_size. | ||||
|  * @param      input_data       Samples to be decoded. The dimensions are | ||||
|  *                              channel (for multi-channel audio), sample. | ||||
|  * @param[out] converted_data   Converted samples. The dimensions are channel | ||||
|  *                              (for multi-channel audio), sample. | ||||
|  * @param      frame_size       Number of samples to be converted | ||||
|  * @param      resample_context Resample context for the conversion | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int convert_samples(uint8_t **input_data, | ||||
|                            uint8_t **converted_data, const int frame_size, | ||||
| @ -434,7 +480,7 @@ static int convert_samples(uint8_t **input_data, | ||||
| { | ||||
|     int error; | ||||
| 
 | ||||
|     /** Convert the samples using the resampler. */ | ||||
|     /* Convert the samples using the resampler. */ | ||||
|     if ((error = avresample_convert(resample_context, converted_data, 0, | ||||
|                                     frame_size, input_data, 0, frame_size)) < 0) { | ||||
|         fprintf(stderr, "Could not convert input samples (error '%s')\n", | ||||
| @ -442,11 +488,9 @@ static int convert_samples(uint8_t **input_data, | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Perform a sanity check so that the number of converted samples is | ||||
|     /* Perform a sanity check so that the number of converted samples is
 | ||||
|      * not greater than the number of samples to be converted. | ||||
|      * If the sample rates differ, this case has to be handled differently | ||||
|      */ | ||||
|      * If the sample rates differ, this case has to be handled differently. */ | ||||
|     if (avresample_available(resample_context)) { | ||||
|         fprintf(stderr, "Converted samples left over\n"); | ||||
|         return AVERROR_EXIT; | ||||
| @ -455,23 +499,28 @@ static int convert_samples(uint8_t **input_data, | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /** Add converted input audio samples to the FIFO buffer for later processing. */ | ||||
| /**
 | ||||
|  * Add converted input audio samples to the FIFO buffer for later processing. | ||||
|  * @param fifo                    Buffer to add the samples to | ||||
|  * @param converted_input_samples Samples to be added. The dimensions are channel | ||||
|  *                                (for multi-channel audio), sample. | ||||
|  * @param frame_size              Number of samples to be converted | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int add_samples_to_fifo(AVAudioFifo *fifo, | ||||
|                                uint8_t **converted_input_samples, | ||||
|                                const int frame_size) | ||||
| { | ||||
|     int error; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Make the FIFO as large as it needs to be to hold both, | ||||
|      * the old and the new samples. | ||||
|      */ | ||||
|     /* Make the FIFO as large as it needs to be to hold both,
 | ||||
|      * the old and the new samples. */ | ||||
|     if ((error = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame_size)) < 0) { | ||||
|         fprintf(stderr, "Could not reallocate FIFO\n"); | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /** Store the new samples in the FIFO buffer. */ | ||||
|     /* Store the new samples in the FIFO buffer. */ | ||||
|     if (av_audio_fifo_write(fifo, (void **)converted_input_samples, | ||||
|                             frame_size) < frame_size) { | ||||
|         fprintf(stderr, "Could not write data to FIFO\n"); | ||||
| @ -481,55 +530,63 @@ static int add_samples_to_fifo(AVAudioFifo *fifo, | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Read one audio frame from the input file, decodes, converts and stores | ||||
|  * Read one audio frame from the input file, decode, convert and store | ||||
|  * it in the FIFO buffer. | ||||
|  * @param      fifo                 Buffer used for temporary storage | ||||
|  * @param      input_format_context Format context of the input file | ||||
|  * @param      input_codec_context  Codec context of the input file | ||||
|  * @param      output_codec_context Codec context of the output file | ||||
|  * @param      resample_context     Resample context for the conversion | ||||
|  * @param[out] finished             Indicates whether the end of file has | ||||
|  *                                  been reached and all data has been | ||||
|  *                                  decoded. If this flag is false, | ||||
|  *                                  there is more data to be decoded, | ||||
|  *                                  i.e., this function has to be called | ||||
|  *                                  again. | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int read_decode_convert_and_store(AVAudioFifo *fifo, | ||||
|                                          AVFormatContext *input_format_context, | ||||
|                                          AVCodecContext *input_codec_context, | ||||
|                                          AVCodecContext *output_codec_context, | ||||
|                                          AVAudioResampleContext *resampler_context, | ||||
|                                          AVAudioResampleContext *resample_context, | ||||
|                                          int *finished) | ||||
| { | ||||
|     /** Temporary storage of the input samples of the frame read from the file. */ | ||||
|     /* Temporary storage of the input samples of the frame read from the file. */ | ||||
|     AVFrame *input_frame = NULL; | ||||
|     /** Temporary storage for the converted input samples. */ | ||||
|     /* Temporary storage for the converted input samples. */ | ||||
|     uint8_t **converted_input_samples = NULL; | ||||
|     int data_present; | ||||
|     int ret = AVERROR_EXIT; | ||||
| 
 | ||||
|     /** Initialize temporary storage for one input frame. */ | ||||
|     /* Initialize temporary storage for one input frame. */ | ||||
|     if (init_input_frame(&input_frame)) | ||||
|         goto cleanup; | ||||
|     /** Decode one frame worth of audio samples. */ | ||||
|     /* Decode one frame worth of audio samples. */ | ||||
|     if (decode_audio_frame(input_frame, input_format_context, | ||||
|                            input_codec_context, &data_present, finished)) | ||||
|         goto cleanup; | ||||
|     /**
 | ||||
|      * If we are at the end of the file and there are no more samples | ||||
|     /* If we are at the end of the file and there are no more samples
 | ||||
|      * in the decoder which are delayed, we are actually finished. | ||||
|      * This must not be treated as an error. | ||||
|      */ | ||||
|      * This must not be treated as an error. */ | ||||
|     if (*finished && !data_present) { | ||||
|         ret = 0; | ||||
|         goto cleanup; | ||||
|     } | ||||
|     /** If there is decoded data, convert and store it */ | ||||
|     /* If there is decoded data, convert and store it. */ | ||||
|     if (data_present) { | ||||
|         /** Initialize the temporary storage for the converted input samples. */ | ||||
|         /* Initialize the temporary storage for the converted input samples. */ | ||||
|         if (init_converted_samples(&converted_input_samples, output_codec_context, | ||||
|                                    input_frame->nb_samples)) | ||||
|             goto cleanup; | ||||
| 
 | ||||
|         /**
 | ||||
|          * Convert the input samples to the desired output sample format. | ||||
|          * This requires a temporary storage provided by converted_input_samples. | ||||
|          */ | ||||
|         /* Convert the input samples to the desired output sample format.
 | ||||
|          * This requires a temporary storage provided by converted_input_samples. */ | ||||
|         if (convert_samples(input_frame->extended_data, converted_input_samples, | ||||
|                             input_frame->nb_samples, resampler_context)) | ||||
|                             input_frame->nb_samples, resample_context)) | ||||
|             goto cleanup; | ||||
| 
 | ||||
|         /** Add the converted input samples to the FIFO buffer for later processing. */ | ||||
|         /* Add the converted input samples to the FIFO buffer for later processing. */ | ||||
|         if (add_samples_to_fifo(fifo, converted_input_samples, | ||||
|                                 input_frame->nb_samples)) | ||||
|             goto cleanup; | ||||
| @ -550,6 +607,10 @@ cleanup: | ||||
| /**
 | ||||
|  * Initialize one input frame for writing to the output file. | ||||
|  * The frame will be exactly frame_size samples large. | ||||
|  * @param[out] frame                Frame to be initialized | ||||
|  * @param      output_codec_context Codec context of the output file | ||||
|  * @param      frame_size           Size of the frame | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int init_output_frame(AVFrame **frame, | ||||
|                              AVCodecContext *output_codec_context, | ||||
| @ -557,28 +618,24 @@ static int init_output_frame(AVFrame **frame, | ||||
| { | ||||
|     int error; | ||||
| 
 | ||||
|     /** Create a new frame to store the audio samples. */ | ||||
|     /* Create a new frame to store the audio samples. */ | ||||
|     if (!(*frame = av_frame_alloc())) { | ||||
|         fprintf(stderr, "Could not allocate output frame\n"); | ||||
|         return AVERROR_EXIT; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Set the frame's parameters, especially its size and format. | ||||
|     /* Set the frame's parameters, especially its size and format.
 | ||||
|      * av_frame_get_buffer needs this to allocate memory for the | ||||
|      * audio samples of the frame. | ||||
|      * Default channel layouts based on the number of channels | ||||
|      * are assumed for simplicity. | ||||
|      */ | ||||
|      * are assumed for simplicity. */ | ||||
|     (*frame)->nb_samples     = frame_size; | ||||
|     (*frame)->channel_layout = output_codec_context->channel_layout; | ||||
|     (*frame)->format         = output_codec_context->sample_fmt; | ||||
|     (*frame)->sample_rate    = output_codec_context->sample_rate; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Allocate the samples of the created frame. This call will make | ||||
|      * sure that the audio frame can hold as many samples as specified. | ||||
|      */ | ||||
|     /* Allocate the samples of the created frame. This call will make
 | ||||
|      * sure that the audio frame can hold as many samples as specified. */ | ||||
|     if ((error = av_frame_get_buffer(*frame, 0)) < 0) { | ||||
|         fprintf(stderr, "Could not allocate output frame samples (error '%s')\n", | ||||
|                 get_error_text(error)); | ||||
| @ -589,30 +646,36 @@ static int init_output_frame(AVFrame **frame, | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /** Global timestamp for the audio frames */ | ||||
| /* Global timestamp for the audio frames. */ | ||||
| static int64_t pts = 0; | ||||
| 
 | ||||
| /** Encode one frame worth of audio to the output file. */ | ||||
| /**
 | ||||
|  * Encode one frame worth of audio to the output file. | ||||
|  * @param      frame                 Samples to be encoded | ||||
|  * @param      output_format_context Format context of the output file | ||||
|  * @param      output_codec_context  Codec context of the output file | ||||
|  * @param[out] data_present          Indicates whether data has been | ||||
|  *                                   decoded | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int encode_audio_frame(AVFrame *frame, | ||||
|                               AVFormatContext *output_format_context, | ||||
|                               AVCodecContext *output_codec_context, | ||||
|                               int *data_present) | ||||
| { | ||||
|     /** Packet used for temporary storage. */ | ||||
|     /* Packet used for temporary storage. */ | ||||
|     AVPacket output_packet; | ||||
|     int error; | ||||
|     init_packet(&output_packet); | ||||
| 
 | ||||
|     /** Set a timestamp based on the sample rate for the container. */ | ||||
|     /* Set a timestamp based on the sample rate for the container. */ | ||||
|     if (frame) { | ||||
|         frame->pts = pts; | ||||
|         pts += frame->nb_samples; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Encode the audio frame and store it in the temporary packet. | ||||
|      * The output audio stream encoder is used to do this. | ||||
|      */ | ||||
|     /* Encode the audio frame and store it in the temporary packet.
 | ||||
|      * The output audio stream encoder is used to do this. */ | ||||
|     if ((error = avcodec_encode_audio2(output_codec_context, &output_packet, | ||||
|                                        frame, data_present)) < 0) { | ||||
|         fprintf(stderr, "Could not encode frame (error '%s')\n", | ||||
| @ -621,7 +684,7 @@ static int encode_audio_frame(AVFrame *frame, | ||||
|         return error; | ||||
|     } | ||||
| 
 | ||||
|     /** Write one audio frame from the temporary packet to the output file. */ | ||||
|     /* Write one audio frame from the temporary packet to the output file. */ | ||||
|     if (*data_present) { | ||||
|         if ((error = av_write_frame(output_format_context, &output_packet)) < 0) { | ||||
|             fprintf(stderr, "Could not write frame (error '%s')\n", | ||||
| @ -639,37 +702,37 @@ static int encode_audio_frame(AVFrame *frame, | ||||
| /**
 | ||||
|  * Load one audio frame from the FIFO buffer, encode and write it to the | ||||
|  * output file. | ||||
|  * @param fifo                  Buffer used for temporary storage | ||||
|  * @param output_format_context Format context of the output file | ||||
|  * @param output_codec_context  Codec context of the output file | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int load_encode_and_write(AVAudioFifo *fifo, | ||||
|                                  AVFormatContext *output_format_context, | ||||
|                                  AVCodecContext *output_codec_context) | ||||
| { | ||||
|     /** Temporary storage of the output samples of the frame written to the file. */ | ||||
|     /* Temporary storage of the output samples of the frame written to the file. */ | ||||
|     AVFrame *output_frame; | ||||
|     /**
 | ||||
|      * Use the maximum number of possible samples per frame. | ||||
|     /* Use the maximum number of possible samples per frame.
 | ||||
|      * If there is less than the maximum possible frame size in the FIFO | ||||
|      * buffer use this number. Otherwise, use the maximum possible frame size | ||||
|      */ | ||||
|      * buffer use this number. Otherwise, use the maximum possible frame size. */ | ||||
|     const int frame_size = FFMIN(av_audio_fifo_size(fifo), | ||||
|                                  output_codec_context->frame_size); | ||||
|     int data_written; | ||||
| 
 | ||||
|     /** Initialize temporary storage for one output frame. */ | ||||
|     /* Initialize temporary storage for one output frame. */ | ||||
|     if (init_output_frame(&output_frame, output_codec_context, frame_size)) | ||||
|         return AVERROR_EXIT; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Read as many samples from the FIFO buffer as required to fill the frame. | ||||
|      * The samples are stored in the frame temporarily. | ||||
|      */ | ||||
|     /* Read as many samples from the FIFO buffer as required to fill the frame.
 | ||||
|      * The samples are stored in the frame temporarily. */ | ||||
|     if (av_audio_fifo_read(fifo, (void **)output_frame->data, frame_size) < frame_size) { | ||||
|         fprintf(stderr, "Could not read data from FIFO\n"); | ||||
|         av_frame_free(&output_frame); | ||||
|         return AVERROR_EXIT; | ||||
|     } | ||||
| 
 | ||||
|     /** Encode one frame worth of audio samples. */ | ||||
|     /* Encode one frame worth of audio samples. */ | ||||
|     if (encode_audio_frame(output_frame, output_format_context, | ||||
|                            output_codec_context, &data_written)) { | ||||
|         av_frame_free(&output_frame); | ||||
| @ -679,7 +742,11 @@ static int load_encode_and_write(AVAudioFifo *fifo, | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /** Write the trailer of the output file container. */ | ||||
| /**
 | ||||
|  * Write the trailer of the output file container. | ||||
|  * @param output_format_context Format context of the output file | ||||
|  * @return Error code (0 if successful) | ||||
|  */ | ||||
| static int write_output_file_trailer(AVFormatContext *output_format_context) | ||||
| { | ||||
|     int error; | ||||
| @ -691,7 +758,6 @@ static int write_output_file_trailer(AVFormatContext *output_format_context) | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /** Convert an audio file to an AAC file in an MP4 container. */ | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|     AVFormatContext *input_format_context = NULL, *output_format_context = NULL; | ||||
| @ -700,89 +766,75 @@ int main(int argc, char **argv) | ||||
|     AVAudioFifo *fifo = NULL; | ||||
|     int ret = AVERROR_EXIT; | ||||
| 
 | ||||
|     if (argc < 3) { | ||||
|     if (argc != 3) { | ||||
|         fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]); | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     /** Register all codecs and formats so that they can be used. */ | ||||
|     /* Register all codecs and formats so that they can be used. */ | ||||
|     av_register_all(); | ||||
|     /** Open the input file for reading. */ | ||||
|     /* Open the input file for reading. */ | ||||
|     if (open_input_file(argv[1], &input_format_context, | ||||
|                         &input_codec_context)) | ||||
|         goto cleanup; | ||||
|     /** Open the output file for writing. */ | ||||
|     /* Open the output file for writing. */ | ||||
|     if (open_output_file(argv[2], input_codec_context, | ||||
|                          &output_format_context, &output_codec_context)) | ||||
|         goto cleanup; | ||||
|     /** Initialize the resampler to be able to convert audio sample formats. */ | ||||
|     /* Initialize the resampler to be able to convert audio sample formats. */ | ||||
|     if (init_resampler(input_codec_context, output_codec_context, | ||||
|                        &resample_context)) | ||||
|         goto cleanup; | ||||
|     /** Initialize the FIFO buffer to store audio samples to be encoded. */ | ||||
|     /* Initialize the FIFO buffer to store audio samples to be encoded. */ | ||||
|     if (init_fifo(&fifo, output_codec_context)) | ||||
|         goto cleanup; | ||||
|     /** Write the header of the output file container. */ | ||||
|     /* Write the header of the output file container. */ | ||||
|     if (write_output_file_header(output_format_context)) | ||||
|         goto cleanup; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Loop as long as we have input samples to read or output samples | ||||
|      * to write; abort as soon as we have neither. | ||||
|      */ | ||||
|     /* Loop as long as we have input samples to read or output samples
 | ||||
|      * to write; abort as soon as we have neither. */ | ||||
|     while (1) { | ||||
|         /** Use the encoder's desired frame size for processing. */ | ||||
|         /* Use the encoder's desired frame size for processing. */ | ||||
|         const int output_frame_size = output_codec_context->frame_size; | ||||
|         int finished                = 0; | ||||
| 
 | ||||
|         /**
 | ||||
|          * Make sure that there is one frame worth of samples in the FIFO | ||||
|         /* Make sure that there is one frame worth of samples in the FIFO
 | ||||
|          * buffer so that the encoder can do its work. | ||||
|          * Since the decoder's and the encoder's frame size may differ, we | ||||
|          * need to FIFO buffer to store as many frames worth of input samples | ||||
|          * that they make up at least one frame worth of output samples. | ||||
|          */ | ||||
|          * that they make up at least one frame worth of output samples. */ | ||||
|         while (av_audio_fifo_size(fifo) < output_frame_size) { | ||||
|             /**
 | ||||
|              * Decode one frame worth of audio samples, convert it to the | ||||
|              * output sample format and put it into the FIFO buffer. | ||||
|              */ | ||||
|             /* Decode one frame worth of audio samples, convert it to the
 | ||||
|              * output sample format and put it into the FIFO buffer. */ | ||||
|             if (read_decode_convert_and_store(fifo, input_format_context, | ||||
|                                               input_codec_context, | ||||
|                                               output_codec_context, | ||||
|                                               resample_context, &finished)) | ||||
|                 goto cleanup; | ||||
| 
 | ||||
|             /**
 | ||||
|              * If we are at the end of the input file, we continue | ||||
|              * encoding the remaining audio samples to the output file. | ||||
|              */ | ||||
|             /* If we are at the end of the input file, we continue
 | ||||
|              * encoding the remaining audio samples to the output file. */ | ||||
|             if (finished) | ||||
|                 break; | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|          * If we have enough samples for the encoder, we encode them. | ||||
|         /* If we have enough samples for the encoder, we encode them.
 | ||||
|          * At the end of the file, we pass the remaining samples to | ||||
|          * the encoder. | ||||
|          */ | ||||
|          * the encoder. */ | ||||
|         while (av_audio_fifo_size(fifo) >= output_frame_size || | ||||
|                (finished && av_audio_fifo_size(fifo) > 0)) | ||||
|             /**
 | ||||
|              * Take one frame worth of audio samples from the FIFO buffer, | ||||
|              * encode it and write it to the output file. | ||||
|              */ | ||||
|             /* Take one frame worth of audio samples from the FIFO buffer,
 | ||||
|              * encode it and write it to the output file. */ | ||||
|             if (load_encode_and_write(fifo, output_format_context, | ||||
|                                       output_codec_context)) | ||||
|                 goto cleanup; | ||||
| 
 | ||||
|         /**
 | ||||
|          * If we are at the end of the input file and have encoded | ||||
|          * all remaining samples, we can exit this loop and finish. | ||||
|          */ | ||||
|         /* If we are at the end of the input file and have encoded
 | ||||
|          * all remaining samples, we can exit this loop and finish. */ | ||||
|         if (finished) { | ||||
|             int data_written; | ||||
|             /** Flush the encoder as it may have delayed frames. */ | ||||
|             /* Flush the encoder as it may have delayed frames. */ | ||||
|             do { | ||||
|                 if (encode_audio_frame(NULL, output_format_context, | ||||
|                                        output_codec_context, &data_written)) | ||||
| @ -792,7 +844,7 @@ int main(int argc, char **argv) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** Write the trailer of the output file container. */ | ||||
|     /* Write the trailer of the output file container. */ | ||||
|     if (write_output_file_trailer(output_format_context)) | ||||
|         goto cleanup; | ||||
|     ret = 0; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user