音視頻處理 ffmpeg中級開發 AAC編碼

介紹

  • 編碼流程類似于視頻編碼,1,查找編碼器;2,設定參數,打開編碼器;3,數據編碼
  • 編碼函數 avcodec_encode_audio2 已經被棄用
  • FFmpeg 過時 Api 匯總整理 - 灰色飄零 - 博客園? 未成功
  • 使用
    • 舊版本
    • if (avcodec_encode_audio2(tmpAvCodecCtx, &pkt_out, frame, &got_picture) < 0)
    • 新版本
    • if(avcodec_send_frame(tmpAvCodecCtx, frame)<0 || (got_picture=avcodec_receive_packet(tmpAvCodecCtx, &pkt_out))<0)?
  • 本文研究的是 官方的例子,并未使用 上述函數

參考鏈接

  • FFmpeg/transcode_aac.c at release/4.1 · FFmpeg/FFmpeg · GitHub? 修改后成功
  • 源碼示例? 存放路徑/home/chy-cpabe/ffmpeg-source/ffmpeg/doc/examples/transcode_aac.c
  • GitHub - FFmpeg/FFmpeg: Mirror of https://git.ffmpeg.org/ffmpeg.git?Github官網
  • 編解碼API的詳細介紹參見 FFmpeg音頻解碼。
  • 轉封裝流程的詳細介紹參見 FFmpeg轉封裝(remuxing)。
  • 其中音頻重采樣流程的介紹見 FFmpeg音頻重采樣API(libswresample)。
  • AVAudioFifo的介紹參見FFmpeg 示例轉封裝轉碼-transcoding。
  • 作者:smallest_one? 鏈接:FFmpeg 示例音頻轉碼為AAC - 簡書
  • AAC編解碼簡析_Geek.Fan的博客-CSDN博客_aac解碼什么意思

注意事項

  • ffplay播放工具 存儲路徑 /home/chy-cpabe/ffmpeg-source/ffmpeg
  • 引入ffmpeg編譯錯誤taking address of temporary array
  • ibavutil/error.h:120:95: 錯誤:taking address of temporary array av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum) 這里使用了的臨時變量作為返回值,因此報錯。把這個宏定義改為一個函數,仍然不可以避免這個報錯
  • normalize_ts.cpp:217:49: error: taking address of temporary array · Issue #5 · joncampbell123/composite-video-simulator · GitHub
  • 補充代碼
#ifdef av_err2str
#undef av_err2str
#include <string>
av_always_inline std::string av_err2string(int errnum) {char str[AV_ERROR_MAX_STRING_SIZE];return av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, errnum);
}
#define av_err2str(err) av_err2string(err).c_str()
#endif  // av_err2str
  • 輸入的文件中只能有一個音頻流,否則會報錯
  • 輸出的音頻的編碼格式為AAC
  • 使用這個示例程序將其他格式的音頻文件比如mp3、wav等格式轉換為aac格式

執行流程

完整代碼

#include <cstdio>
#include <cstdlib>
#include <cstdint>extern "C" {
#include<libavcodec/avcodec.h>#include "libavformat/avformat.h"
#include "libavformat/avio.h"#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.h>
#include <libavutil/audio_fifo.h>
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/opt.h"#include "libswresample/swresample.h"
}/** Copyright (c) 2013-2022 Andreas Unterweger** This file is part of FFmpeg.** FFmpeg is free software; you can redistribute it and/or* modify it under the terms of the GNU Lesser General Public* License as published by the Free Software Foundation; either* version 2.1 of the License, or (at your option) any later version.** FFmpeg is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU* Lesser General Public License for more details.** You should have received a copy of the GNU Lesser General Public* License along with FFmpeg; if not, write to the Free Software* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*//*** @file* Simple audio converter** @example transcode_aac.c* Convert an input audio file to AAC in an MP4 container using FFmpeg.* Formats other than MP4 are supported based on the output file extension.* @author Andreas Unterweger (dustsigns@gmail.com)*//* The output bit rate in bit/s */
#define OUTPUT_BIT_RATE 96000
/* The number of output channels */
#define OUTPUT_CHANNELS 2#ifdef av_err2str
#undef av_err2str
#include <string>
av_always_inline std::string av_err2string(int errnum) {char str[AV_ERROR_MAX_STRING_SIZE];return av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, errnum);
}
#define av_err2str(err) av_err2string(err).c_str()
#endif  // av_err2str/*** 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)
{AVCodecContext *avctx;const AVCodec *input_codec;const AVStream *stream;int error;/* 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",filename, av_err2str(error));*input_format_context = NULL;return error;}/* 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",av_err2str(error));avformat_close_input(input_format_context);return error;}/* 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);avformat_close_input(input_format_context);return AVERROR_EXIT;}stream = (*input_format_context)->streams[0];/* Find a decoder for the audio stream. */if (!(input_codec = avcodec_find_decoder(stream->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. */avctx = avcodec_alloc_context3(input_codec);if (!avctx) {fprintf(stderr, "Could not allocate a decoding context\n");avformat_close_input(input_format_context);return AVERROR(ENOMEM);}/* Initialize the stream parameters with demuxer information. */error = avcodec_parameters_to_context(avctx, stream->codecpar);if (error < 0) {avformat_close_input(input_format_context);avcodec_free_context(&avctx);return error;}/* 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",av_err2str(error));avcodec_free_context(&avctx);avformat_close_input(input_format_context);return error;}/* Set the packet timebase for the decoder. */avctx->pkt_timebase = stream->time_base;/* Save the decoder context for easier access later. */*input_codec_context = avctx;return 0;
}/*** 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,AVFormatContext **output_format_context,AVCodecContext **output_codec_context)
{AVCodecContext *avctx          = NULL;AVIOContext *output_io_context = NULL;AVStream *stream               = NULL;const AVCodec *output_codec    = NULL;int error;/* 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",filename, av_err2str(error));return error;}/* 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. */(*output_format_context)->pb = output_io_context;/* 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");goto cleanup;}if (!((*output_format_context)->url = av_strdup(filename))) {fprintf(stderr, "Could not allocate url.\n");error = AVERROR(ENOMEM);goto cleanup;}/* 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. */if (!(stream = avformat_new_stream(*output_format_context, NULL))) {fprintf(stderr, "Could not create new stream\n");error = AVERROR(ENOMEM);goto cleanup;}avctx = avcodec_alloc_context3(output_codec);if (!avctx) {fprintf(stderr, "Could not allocate an encoding context\n");error = AVERROR(ENOMEM);goto cleanup;}/* Set the basic encoder parameters.* The input file's sample rate is used to avoid a sample rate conversion. */av_channel_layout_default(&avctx->ch_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;/* 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. */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. */if ((error = avcodec_open2(avctx, output_codec, NULL)) < 0) {fprintf(stderr, "Could not open output codec (error '%s')\n",av_err2str(error));goto cleanup;}error = avcodec_parameters_from_context(stream->codecpar, avctx);if (error < 0) {fprintf(stderr, "Could not initialize stream parameters\n");goto cleanup;}/* Save the encoder context for easier access later. */*output_codec_context = avctx;return 0;cleanup:avcodec_free_context(&avctx);avio_closep(&(*output_format_context)->pb);avformat_free_context(*output_format_context);*output_format_context = NULL;return error < 0 ? error : AVERROR_EXIT;
}/*** Initialize one data packet for reading or writing.* @param[out] packet Packet to be initialized* @return Error code (0 if successful)*/
static int init_packet(AVPacket **packet)
{if (!(*packet = av_packet_alloc())) {fprintf(stderr, "Could not allocate packet\n");return AVERROR(ENOMEM);}return 0;
}/*** 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())) {fprintf(stderr, "Could not allocate input frame\n");return AVERROR(ENOMEM);}return 0;
}/*** Initialize the audio resampler based on the input and output codec settings.* If the input and output sample formats differ, a conversion is required* libswresample 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,SwrContext **resample_context)
{int error;/** Create a resampler context for the conversion.* Set the conversion parameters.*/error = swr_alloc_set_opts2(resample_context,&output_codec_context->ch_layout,output_codec_context->sample_fmt,output_codec_context->sample_rate,&input_codec_context->ch_layout,input_codec_context->sample_fmt,input_codec_context->sample_rate,0, NULL);if (error < 0) {fprintf(stderr, "Could not allocate resample context\n");return error;}/** 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*/av_assert0(output_codec_context->sample_rate == input_codec_context->sample_rate);/* Open the resampler with the specified parameters. */if ((error = swr_init(*resample_context)) < 0) {fprintf(stderr, "Could not open resample context\n");swr_free(resample_context);return error;}return 0;
}/*** 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. */if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt,output_codec_context->ch_layout.nb_channels, 1))) {fprintf(stderr, "Could not allocate FIFO\n");return AVERROR(ENOMEM);}return 0;
}/*** 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;if ((error = avformat_write_header(output_format_context, NULL)) < 0) {fprintf(stderr, "Could not write output file header (error '%s')\n",av_err2str(error));return error;}return 0;
}/*** 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. */AVPacket *input_packet;int error;error = init_packet(&input_packet);if (error < 0)return error;*data_present = 0;*finished = 0;/* 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 at the end of the file, flush the decoder below. */if (error == AVERROR_EOF)*finished = 1;else {fprintf(stderr, "Could not read frame (error '%s')\n",av_err2str(error));goto cleanup;}}/* Send the audio frame stored in the temporary packet to the decoder.* The input audio stream decoder is used to do this. */if ((error = avcodec_send_packet(input_codec_context, input_packet)) < 0) {fprintf(stderr, "Could not send packet for decoding (error '%s')\n",av_err2str(error));goto cleanup;}/* Receive one frame from the decoder. */error = avcodec_receive_frame(input_codec_context, frame);/* If the decoder asks for more data to be able to decode a frame,* return indicating that no data is present. */if (error == AVERROR(EAGAIN)) {error = 0;goto cleanup;/* If the end of the input file is reached, stop decoding. */} else if (error == AVERROR_EOF) {*finished = 1;error = 0;goto cleanup;} else if (error < 0) {fprintf(stderr, "Could not decode frame (error '%s')\n",av_err2str(error));goto cleanup;/* Default case: Return decoded data. */} else {*data_present = 1;goto cleanup;}cleanup:av_packet_free(&input_packet);return error;
}/*** 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,int frame_size)
{int error;/* 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).*/if (!(*converted_input_samples = static_cast<uint8_t **>(calloc(output_codec_context->ch_layout.nb_channels,sizeof(**converted_input_samples))))) {fprintf(stderr, "Could not allocate converted input sample pointers\n");return AVERROR(ENOMEM);}/* 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->ch_layout.nb_channels,frame_size,output_codec_context->sample_fmt, 0)) < 0) {fprintf(stderr,"Could not allocate converted input samples (error '%s')\n",av_err2str(error));av_freep(&(*converted_input_samples)[0]);free(*converted_input_samples);return error;}return 0;
}/*** 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.* @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(const uint8_t **input_data,uint8_t **converted_data, const int frame_size,SwrContext *resample_context)
{int error;/* Convert the samples using the resampler. */if ((error = swr_convert(resample_context,converted_data, frame_size,input_data    , frame_size)) < 0) {fprintf(stderr, "Could not convert input samples (error '%s')\n",av_err2str(error));return error;}return 0;
}/*** 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. */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. */if (av_audio_fifo_write(fifo, (void **)converted_input_samples,frame_size) < frame_size) {fprintf(stderr, "Could not write data to FIFO\n");return AVERROR_EXIT;}return 0;
}/*** 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      resampler_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,SwrContext *resampler_context,int *finished)
{/* Temporary storage of the input samples of the frame read from the file. */AVFrame *input_frame = NULL;/* 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. */if (init_input_frame(&input_frame))goto cleanup;/* 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* in the decoder which are delayed, we are actually finished.* This must not be treated as an error. */if (*finished) {ret = 0;goto cleanup;}/* If there is decoded data, convert and store it. */if (data_present) {/* 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. */if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples,input_frame->nb_samples, resampler_context))goto cleanup;/* 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;ret = 0;}ret = 0;cleanup:if (converted_input_samples) {av_freep(&converted_input_samples[0]);free(converted_input_samples);}av_frame_free(&input_frame);return ret;
}/*** 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,int frame_size)
{int error;/* 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.* 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. */(*frame)->nb_samples     = frame_size;av_channel_layout_copy(&(*frame)->ch_layout, &output_codec_context->ch_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. */if ((error = av_frame_get_buffer(*frame, 0)) < 0) {fprintf(stderr, "Could not allocate output frame samples (error '%s')\n",av_err2str(error));av_frame_free(frame);return error;}return 0;
}/* Global timestamp for the audio frames. */
static int64_t pts = 0;/*** 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*                                   encoded* @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. */AVPacket *output_packet;int error;error = init_packet(&output_packet);if (error < 0)return error;/* Set a timestamp based on the sample rate for the container. */if (frame) {frame->pts = pts;pts += frame->nb_samples;}*data_present = 0;/* Send the audio frame stored in the temporary packet to the encoder.* The output audio stream encoder is used to do this. */error = avcodec_send_frame(output_codec_context, frame);/* Check for errors, but proceed with fetching encoded samples if the*  encoder signals that it has nothing more to encode. */if (error < 0 && error != AVERROR_EOF) {fprintf(stderr, "Could not send packet for encoding (error '%s')\n",av_err2str(error));goto cleanup;}/* Receive one encoded frame from the encoder. */error = avcodec_receive_packet(output_codec_context, output_packet);/* If the encoder asks for more data to be able to provide an* encoded frame, return indicating that no data is present. */if (error == AVERROR(EAGAIN)) {error = 0;goto cleanup;/* If the last frame has been encoded, stop encoding. */} else if (error == AVERROR_EOF) {error = 0;goto cleanup;} else if (error < 0) {fprintf(stderr, "Could not encode frame (error '%s')\n",av_err2str(error));goto cleanup;/* Default case: Return encoded data. */} else {*data_present = 1;}/* Write one audio frame from the temporary packet to the output file. */if (*data_present &&(error = av_write_frame(output_format_context, output_packet)) < 0) {fprintf(stderr, "Could not write frame (error '%s')\n",av_err2str(error));goto cleanup;}cleanup:av_packet_free(&output_packet);return error;
}/*** 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. */AVFrame *output_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. */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. */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. */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. */if (encode_audio_frame(output_frame, output_format_context,output_codec_context, &data_written)) {av_frame_free(&output_frame);return AVERROR_EXIT;}av_frame_free(&output_frame);return 0;
}/*** 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;if ((error = av_write_trailer(output_format_context)) < 0) {fprintf(stderr, "Could not write output file trailer (error '%s')\n",av_err2str(error));return error;}return 0;
}int main(int argc, char **argv)
{AVFormatContext *input_format_context = NULL, *output_format_context = NULL;AVCodecContext *input_codec_context = NULL, *output_codec_context = NULL;SwrContext *resample_context = NULL;AVAudioFifo *fifo = NULL;int ret = AVERROR_EXIT;if (argc != 3) {fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);exit(1);}/* 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. */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. */if (init_resampler(input_codec_context, output_codec_context,&resample_context))goto cleanup;/* 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. */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. */while (1) {/* 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* 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. */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. */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 (finished)break;}/* 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. */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. */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 (finished) {int data_written;/* Flush the encoder as it may have delayed frames. */do {if (encode_audio_frame(NULL, output_format_context,output_codec_context, &data_written))goto cleanup;} while (data_written);break;}}/* Write the trailer of the output file container. */if (write_output_file_trailer(output_format_context))goto cleanup;ret = 0;cleanup:if (fifo)av_audio_fifo_free(fifo);swr_free(&resample_context);if (output_codec_context)avcodec_free_context(&output_codec_context);if (output_format_context) {avio_closep(&output_format_context->pb);avformat_free_context(output_format_context);}if (input_codec_context)avcodec_free_context(&input_codec_context);if (input_format_context)avformat_close_input(&input_format_context);return ret;
}

?

執行結果

CLion

?MP3

?aac

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446031.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446031.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446031.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

虛擬機為Ubuntu分配空間

當虛擬機里面的創建的ubuntu鏡像需要更大的空間&#xff0c;將ubuntu關掉之后&#xff0c;對應調整硬盤的空間大小&#xff0c;由先前的20G上調至50G&#xff0c;但是先前的20G內存空間映射的位置是/dev/sda&#xff0c;后面增加的這段內存空間30G映射到/dev/sda1因此&#xff…

為什么人會擺高姿態_Yo , 你為什么喜歡沖浪?

“你為什么喜歡沖浪&#xff1f;” 那天木木突然問我。我愣住了。此時一道碧波恰從防潑堤&#xff08;jetty&#xff09;的那頭升起&#xff0c;木木轉頭望去&#xff0c;視線追著那道浪緩緩向西&#xff0c;直至它破碎成白色的浪花。我瞥見他眼神中的光亮&#xff0c;就和小孩…

音視頻處理 ffmpeg初級開發 命令行工具-實用命令

參考鏈接 ffmpeg Documentation作者&#xff1a;smallest_one 鏈接&#xff1a;FFmpeg命令行工具-實用命令 - 簡書 目錄 1&#xff0c;help命令使用 1.1 ffmpeg命令的語法結構1.2 獲取詳細的help信息1.3 打印幫助或者支持能力的信息1.4 全局選項1.5 文件選項1.6 視頻/音頻/字…

不同的電腦打印預覽不同怎么解決_條碼打印軟件中標簽預覽正常打印無反應怎么解決...

在使用條碼打印軟件制作標簽時&#xff0c;有客戶反饋,標簽打印預覽正常的&#xff0c;但是打印無反應&#xff0c;咨詢是怎么回事?今天針對這個情況&#xff0c;可以參考以下方法進行解決。一、預覽正常情況下&#xff0c;打印沒反應(1)在條碼打印軟件中設計好標簽之后&#…

python安裝scrapy_Python安裝Scrapy的種種

這幾天沒什么事&#xff0c;決定把自己抓代理的小工具用scrapy改寫。然而安裝的時候卻出現以下問題&#xff0c;反復失敗&#xff1a;Unable to find vcvarsall.bat經過一番查找&#xff0c;找到了這個文件&#xff1a;\Lib\distutils\_msvccompiler.py它里邊長這樣&#xff1a…

MP4文件格式的相關內容

參考鏈接 FFmpeg中mp4的demuxer(mov.c)代碼閱讀 - 簡書mp4文件格式解析 - 簡書mp4封裝格式各box類型講解及IBP幀計算_青丶空゛的博客-CSDN博客5分鐘入門MP4文件格式 - 程序猿小卡 - 博客園?關于M4A文件的隨機訪問 - 云社區 - 騰訊云 MP4文件格式相關內容 MP4文件由許多box組…

華三交換機如何進入配置_學校機房項目交換機的如何配置,理解這篇,交換機配置不再難...

弱電項目中&#xff0c;交換機的配置是無法避免的&#xff0c;大部分的項目都有可能會涉及到&#xff0c;尤其是機房等網絡項目&#xff0c;本期我們就通過一個實際項目案例來詳細了解交換機在項目中的應用配置&#xff0c;如果我們平時對交換機配置不熟&#xff0c;這個案例可…

百度地圖遷徙大數據_百度地圖大數據:五一高速擁堵不似預期,廣深成熱門遷出入地...

五一假期在即&#xff0c;你是否做好了“出行功課”&#xff1f;高速擁堵水平降低、公眾出門不出城、公園成踏青賞景熱門目的地……在全國疫情防控仍未松懈的時刻&#xff0c;2020年的五一或許注定與往年不同。近日&#xff0c;百度地圖發布2020五一假期安全出行大數據&#xf…

音視頻的基礎知識 視頻播放器原理/封裝格式/視頻音頻編碼數據/視頻像素數據/音頻采樣數據

參考鏈接 FFMpeg視頻播放器的制作-雷霄驊&#xff08;去除電流音版本&#xff09;_嗶哩嗶哩_bilibili 視頻播放器原理 播放視頻文件的流程YUV是一張屏幕中像素點的數值封裝格式 MP4 RMVB TS FLV AVI將視頻和音頻碼流按照一定的格式存儲在一個文件中封裝格式分析工具&#xf…

科立捷7代寫頻軟件_天大廈大“兩碩士論文雷同”通報,代寫買賣論文

澎湃新聞記者 薛莎莎天津大學、廈門大學7月10日晚就“兩碩士論文雷同”一事&#xff0c;分別發出調查處理通報。通報稱&#xff0c;涉事兩名學生存在由他人代寫、買賣論文的學術作假的行為&#xff0c;均撤銷其所獲碩士學位&#xff0c;收回、注銷碩士學位證書。澎湃新聞注意到…

FFMpeg命令行基礎

參考鏈接 FFMpeg視頻播放器的制作-雷霄驊&#xff08;去除電流音版本&#xff09;_嗶哩嗶哩_bilibili音視頻處理 ffmpeg初級開發 命令行工具-實用命令_MY CUP OF TEA的博客-CSDN博客 介紹 FFMpeg是視頻播放和轉碼的內核 使用 win中ffmpeg.exe用于視頻轉碼簡單命令&#xff1…

悲觀鎖和樂觀鎖_面試必備之樂觀鎖與悲觀鎖

何謂悲觀鎖與樂觀鎖樂觀鎖對應于生活中樂觀的人總是想著事情往好的方向發展&#xff0c;悲觀鎖對應于生活中悲觀的人總是想著事情往壞的方向發展。這兩種人各有優缺點&#xff0c;不能不以場景而定說一種人好于另外一種人。大家可以點擊加群【JAVA架構知識學習討論群】47398464…

Microsoft Visual Studio2019環境下搭建FFmpeg開發環境

參考鏈接 《基于 FFmpeg SDL 的視頻播放器的制作》課程的視頻_雷霄驊的博客-CSDN博客_雷霄驊ffmpeg視頻教程小學期課程資料 - 基于FFmpegSDL的視頻播放器的制作.zip_免費高速下載|百度網盤-分享無限制輔助參考鏈接使用VS2019創建項目&#xff0c;添加文件和庫地址_MY CUP OF …

vue process.env獲取不到_從文檔開始,重學vue(下)源碼級別

此篇文章主要是從應用及源碼層面講解vue部分常用api,閱讀起來可能略有難度,新手可以看《從文檔開始,重學vue(上)》示例代碼均在vue-cli3中完成Vue.extend()可以使用 extend 創建一個子類,該方法通常用于構建全局組件,如彈框組件等,下面我們就用它來制作個全局alert組件吧首先我…

Microsoft Visual Studio2019環境下搭建SDL開發環境

參考鏈接 《基于 FFmpeg SDL 的視頻播放器的制作》課程的視頻_雷霄驊的博客-CSDN博客_雷霄驊ffmpeg視頻教程小學期課程資料 - 基于FFmpegSDL的視頻播放器的制作.zip_免費高速下載|百度網盤-分享無限制輔助參考鏈接VS自動鏈接到Windows上隨vcpkg安裝的SDL2庫 | 碼農俱樂部 - G…

不關注公眾號可以獲取openid嗎_微信公眾號粉絲遷移

目錄 [toc] 微信公眾號遷移 正常的公眾號遷移直接通過微信操作就可以&#xff0c;如下圖。但是因為udb數據里面存的是遷移前公眾號的openid以及unionid,需要自行獲取新舊openid以及unionid。 舊的用戶信息要在遷移之前獲取&#xff0c;第三步點擊同意之后就公眾號的接口就調不通…

建筑專業規范大全 2020版_房屋建筑工程現行規范標準目錄匯編(2020版)—建筑電氣...

房屋建筑工程現行規范標準目錄匯編(2020版)建筑電氣規范編號規范名稱GB 50034-2013建筑照明設計標準GB 50052-2009供配電系統設計規范GB 50053-201320kV及以下變電所設計規范GB 50057-2010建筑物防雷設計規范GB 50147-2010電氣裝置安裝工程 高壓電器施工及驗收規范GB 50148-201…

基于Microsoft Visual Studio2019環境編寫ffmpeg視頻解碼代碼

舊代碼 舊代碼使用了很多過時的API&#xff0c;這些API使用后&#xff0c;vs會報編譯器警告 (級別 3) C4996的錯誤即 函數被聲明為已否決 報 C4996的錯誤 // test_ffmpeg.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。 // #define SDL_MAIN_HANDLED …

16進制轉double dotnet_終于把計算機進制弄明白了!

And theres one thing that I need from you我只需要你為我做一-件事Can you come through, through待在我的身邊就好Through, yeah你可以撫慰一切不滿And theres one thing that I need from you你可以過來Can you come through?待在我的身邊嗎-comethruJeremy Zucker進制進制…

FFmpeg源代碼簡單分析-架構圖-解碼

參考鏈接 FFmpeg源代碼結構圖 - 解碼_雷霄驊的博客-CSDN博客_ffmpeg雷霄驊函數背景色 函數在圖中以方框的形式表現出來。不同的背景色標志了該函數不同的作用&#xff1a; 粉紅色背景函數&#xff1a;FFmpeg的API函數。白色背景的函數&#xff1a;FFmpeg的內部函數。黃色背景…