音频解码

一、初始化阶段
- avformat_open_input
打开输入媒体文件。
- avformat_find_stream_info
读取媒体流信息,查找音频流。
- avcodec_find_decoder
查找对应的解码器(如 AAC、MP3 解码器)。
- avcodec_alloc_context3
分配解码器上下文。
- avcodec_open2
打开解码器。
- av_packet_alloc
分配 AVPacket
用于读取压缩数据。
- av_frame_alloc
分配 AVFrame
用于接收解码后的原始音频帧。
二、解码循环阶段
- av_read_frame
从输入文件中读取一个压缩包(Packet)。
- 读取判断
- 如果读取成功(true):
- avcodec_send_packet:将压缩数据送入解码器。
- avcodec_receive_frame:从解码器取出解码后的音频帧。
- 写文件:将解码后的音频帧保存或播放处理。
- 如果读取失败(false):
#include <QDebug>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
}
int main()
{
const char inFileName[] = "output.aac";
const char outFileName[] = "test.pcm";
FILE *file = fopen(outFileName, "wb+");
if (!file) {
qDebug() << "Cannot open output file";
return -1;
}
AVFormatContext *fmtCtx = avformat_alloc_context();
AVCodecContext *codecCtx = NULL;
AVPacket *pkt = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
int aStreamIndex = -1;
do {
if (avformat_open_input(&fmtCtx, inFileName, NULL, NULL) < 0) {
qDebug() << "Cannot open input file";
return -1;
}
if (avformat_find_stream_info(fmtCtx, NULL) < 0) {
qDebug() << "Cannot find any stream in file";
return -1;
}
for (size_t i = 0; i < fmtCtx->nb_streams; i++) {
if (fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
aStreamIndex = (int)i;
break;
}
}
if (aStreamIndex == -1) {
qDebug() << "Cannot find audio stream";
return -1;
}
AVCodecParameters *aCodecPara = fmtCtx->streams[aStreamIndex]->codecpar;
const AVCodec *codec = avcodec_find_decoder(aCodecPara->codec_id);
if (!codec) {
qDebug() << "Cannot find any codec for audio";
return -1;
}
codecCtx = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(codecCtx, aCodecPara) < 0) {
qDebug() << "Cannot alloc codec context";
return -1;
}
codecCtx->pkt_timebase = fmtCtx->streams[aStreamIndex]->time_base;
if (avcodec_open2(codecCtx, codec, NULL) < 0) {
qDebug() << "Cannot open audio codec";
return -1;
}
while (av_read_frame(fmtCtx, pkt) >= 0) {
if (pkt->stream_index == aStreamIndex) {
if (avcodec_send_packet(codecCtx, pkt) >= 0) {
while (avcodec_receive_frame(codecCtx, frame) >= 0) {
if (av_sample_fmt_is_planar(codecCtx->sample_fmt)) {
int numBytes = av_get_bytes_per_sample(codecCtx->sample_fmt);
for (int i = 0; i < frame->nb_samples; i++) {
for (int ch = 0; ch < codecCtx->channels; ch++) {
fwrite((char*)frame->data[ch] + numBytes * i, 1, numBytes, file);
}
}
}
}
}
}
av_packet_unref(pkt);
}
} while (0);
av_frame_free(&frame);
av_packet_free(&pkt);
avcodec_close(codecCtx);
avcodec_free_context(&codecCtx);
avformat_free_context(fmtCtx);
fclose(file);
return 0;
}
视频解码

int main(int argc, char *argv[]) {
const char *inputFileName = "C:\\Users\\edoYun\\Videos\\output.h264";
const char *outputFileName = "out.yuv";
AVFormatContext *formatCtx = avformat_alloc_context();
if (avformat_open_input(&formatCtx, inputFileName, NULL, NULL) != 0) {
qDebug() << "Error: could not open input file";
return -1;
}
if (avformat_find_stream_info(formatCtx, NULL) < 0) {
qDebug() << "Error: could not find stream information";
avformat_close_input(&formatCtx);
return -1;
}
int videoStream = -1;
for (int i = 0; i < formatCtx->nb_streams; i++) {
if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
}
}
if (videoStream == -1) {
qDebug() << "Error: could not find video stream";
avformat_close_input(&formatCtx);
return -1;
}
AVCodecParameters *codecParams = formatCtx->streams[videoStream]->codecpar;
const AVCodec *codec = avcodec_find_decoder(codecParams->codec_id);
if (!codec) {
qDebug() << "Error: unsupported codec";
avformat_close_input(&formatCtx);
return -1;
}
AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codecCtx, codecParams);
if (avcodec_open2(codecCtx, codec, NULL) < 0) {
qDebug() << "Error: could not open codec";
avformat_close_input(&formatCtx);
return -1;
}
FILE *outputFile = fopen(outputFileName, "wb");
if (!outputFile) {
qDebug() << "Error: could not open output file";
avcodec_close(codecCtx);
avformat_close_input(&formatCtx);
return -1;
}
AVFrame *frame = av_frame_alloc();
AVPacket packet;
av_init_packet(&packet);
int ret = 0;
while (av_read_frame(formatCtx, &packet) >= 0) {
if (packet.stream_index == videoStream) {
ret = avcodec_send_packet(codecCtx, &packet);
if (ret < 0) {
qDebug() << "Error: sending packet to decoder";
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codecCtx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
qDebug() << "Error: receiving frame from decoder";
break;
}
for (int i = 0; i < frame->height; i++) {
fwrite(frame->data[0] + i * frame->linesize[0], 1, frame->width, outputFile);
}
for (int i = 0; i < frame->height / 2; i++) {
fwrite(frame->data[1] + i * frame->linesize[1], 1, frame->width / 2, outputFile);
}
for (int i = 0; i < frame->height / 2; i++) {
fwrite(frame->data[2] + i * frame->linesize[2], 1, frame->width / 2, outputFile);
}
}
}
av_packet_unref(&packet);
}
fclose(outputFile);
av_frame_free(&frame);
avcodec_close(codecCtx);
avformat_close_input(&formatCtx);
qDebug() << "Finished decoding and writing YUV420 file";
}