FFmpeg源码剖析-通用:get_input_packet()

get_input_packet()位于ffmpeg.c

1. 函数概述

调用av_read_frame()函数从文件中读取一个packet, 
对视频来说,一个packet是一帧;
对音频来说,一个packet是多帧;


2. 函数调用图



3. 代码分析

static int get_input_packet(InputFile *f, AVPacket *pkt)
{
    if (f->rate_emu) {
      ...
    }


    return av_read_frame(f->ctx, pkt);
}



ffmpeg音频编码学习std::vector<uint8_t> convert_pcm_to_alaw(uint8_t *pcm_data, int pcm_size, int input_sample_rate, AVSampleFormat input_fmt, const AVChannelLayout &input_ch_layout) { std::vector<uint8_t> audio_data; //----------------------------- // 1. 初始化编码器(G.711 A-law) //----------------------------- const AVCodec *enc_codec = avcodec_find_encoder(AV_CODEC_ID_PCM_ALAW); AVCodecContext *enc_ctx = avcodec_alloc_context3(enc_codec); enc_ctx->sample_rate = 8000; // 目标采样率 enc_ctx->sample_fmt = AV_SAMPLE_FMT_S16; // 编码器支持的输入格式 av_channel_layout_copy(&enc_ctx->ch_layout, &AV_CHANNEL_LAYOUT_MONO); // 单声道 avcodec_open2(enc_ctx, enc_codec, nullptr); //----------------------------- // 2. 初始化重采样器(SwrContext) //----------------------------- SwrContext *swr = swr_alloc(); av_opt_set_chlayout(swr, "in_chlayout", &input_ch_layout, 0); av_opt_set_int(swr, "in_sample_rate", input_sample_rate, 0); av_opt_set_sample_fmt(swr, "in_sample_fmt", input_fmt, 0); av_opt_set_chlayout(swr, "out_chlayout", &enc_ctx->ch_layout, 0); av_opt_set_int(swr, "out_sample_rate", enc_ctx->sample_rate, 0); av_opt_set_sample_fmt(swr, "out_sample_fmt", enc_ctx->sample_fmt, 0); swr_init(swr); //----------------------------- // 3. 将输入的PCM数据封装到AVFrame //----------------------------- AVFrame *input_frame = av_frame_alloc(); // 更名:避免"解码"歧义 input_frame->format = input_fmt; av_channel_layout_copy(&input_frame->ch_layout, &input_ch_layout); input_frame->nb_samples = pcm_size / (av_get_bytes_per_sample(input_fmt) * input_ch_layout.nb_channels); av_frame_get_buffer(input_frame, 0); memcpy(input_frame->data[0], pcm_data, pcm_size); //----------------------------- // 4. 重采样到目标格式(8kHz单声道S16) //----------------------------- AVFrame *resampled_frame = av_frame_alloc(); resampled_frame->nb_samples = swr_get_out_samples(swr, input_frame->nb_samples); resampled_frame->format = enc_ctx->sample_fmt; av_channel_layout_copy(&resampled_frame->ch_layout, &enc_ctx->ch_layout); av_frame_get_buffer(resampled_frame, 0); swr_convert(swr, resampled_frame->data, resampled_frame->nb_samples, (const uint8_t **)input_frame->data, input_frame->nb_samples); //----------------------------- // 5. 编码为G.711 A-law //----------------------------- AVPacket *enc_pkt = av_packet_alloc(); avcodec_send_frame(enc_ctx, resampled_frame); while (avcodec_receive_packet(enc_ctx, enc_pkt) >= 0) { audio_data.insert(audio_data.end(), enc_pkt->data, enc_pkt->data + enc_pkt->size); av_packet_unref(enc_pkt); } //----------------------------- // 6. 释放资源 //----------------------------- av_frame_free(&input_frame); av_frame_free(&resampled_frame); av_packet_free(&enc_pkt); avcodec_free_context(&enc_ctx); swr_free(&swr); return audio_data; } 这段代码有啥问题吗?
最新发布
05-17
### FFmpeg PCM 转 G.711 A-law 编码函数 `convert_pcm_to_alaw` 的实现分析 在 FFmpeg 中,音频编码涉及多个阶段的处理过程。对于将 PCM 数据转换为 G.711 A-law 格式的功能,通常会通过调用特定的 API 或者自定义逻辑完成。以下是关于 `convert_pcm_to_alaw` 实现可能存在的问题及其原因分析。 #### 1. **采样格式兼容性** FFmpeg 支持多种音频采样格式(如 S16、S8 和 F32),但在执行 PCM 到 A-law 的转换时,输入数据的采样格式必须与预期一致。如果输入的是浮点型数据(例如 AV_SAMPLE_FMT_FLTP),而未经过预处理,则可能导致错误的结果或溢出[^4]。 解决方案是在调用 `convert_pcm_to_alaw` 前,确保输入数据已正确转换为目标采样格式(通常是 S16)。可以通过 `av_audio_convert()` 或其他工具进行必要的格式转换: ```c // 示例代码:将任意采样格式转换为 S16 struct SwrContext *swr_ctx = swr_alloc(); if (!swr_ctx || av_opt_set_int(swr_ctx, "in_channel_layout", input_layout, 0) < 0 || av_opt_set_int(swr_ctx, "out_channel_layout", output_layout, 0) < 0 || av_opt_set_int(swr_ctx, "in_sample_rate", input_sample_rate, 0) < 0 || av_opt_set_int(swr_ctx, "out_sample_rate", output_sample_rate, 0) < 0 || av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", input_format, 0) < 0 || av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0) < 0 || swr_init(swr_ctx) < 0) { fprintf(stderr, "Could not allocate resampler context\n"); exit(1); } ``` #### 2. **量化误差** A-law 是一种非线性压缩算法,在 PCM 数据映射到 A-law 表格的过程中可能会引入量化误差。这种误差主要来源于原始 PCM 数据范围与目标表格之间的不匹配。因此,需要仔细校验 `convert_pcm_to_alaw` 是否正确实现了标准的 A-law 映射表[^1]。 标准 A-law 公式如下所示: \[ y = \text{sgn}(x) \times (A |x| / (1 + \log(A))) \] 其中 \( A=87.6 \),\( x \) 是归一化的 PCM 输入值,\( y \) 是对应的 A-law 输出值。 #### 3. **性能优化不足** 在某些场景下,直接逐样本计算 A-law 变换效率较低。为了提高性能,可以预先构建查找表(Lookup Table),从而减少运行时开销。然而,如果 `convert_pcm_to_alaw` 并未采用此类优化策略,则可能导致不必要的资源浪费[^2]。 示例代码展示如何利用 LUT 提升速度: ```c static const uint8_t alaw_table[256]; void init_alaw_lut() { for (int i = -32768; i <= 32767; ++i) { int sgn = (i >= 0) ? 1 : -1; double abs_val = fabs(i); double compressed = log1p(abs_val / 32767.0 * 87.6) / log(87.6); alaw_table[i + 32768] = ((compressed * 128) & 0xFF) ^ (sgn << 7); } } uint8_t convert_pcm_to_alaw(int pcm_value) { return alaw_table[pcm_value + 32768]; } ``` #### 4. **边界条件处理不当** 当输入信号接近最大幅度(±32767)或其他极端情况时,部分实现可能存在越界访问风险。务必验证 `convert_pcm_to_alaw` 对这些特殊情况进行了适当保护措施[^3]。 --- ### 总结 通过对以上几个方面的深入探讨可知,`convert_pcm_to_alaw` 的潜在缺陷主要包括但不限于以下几个方面:采样格式适配不良、量化精度偏差较大、缺乏高效的查表机制以及异常状况下的鲁棒性较差等问题。针对这些问题提出了相应的改进建议和技术手段以供参考。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北雨南萍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值