AVPacket是存储压缩编码数据相关信息的结构体
例如对于H.264来说。1个AVPacket的data通常对应一个NAL。【注意:此处强调是“通常”,不是“所有”】
注意:在这里只是对应,而不是一模一样。他们之间有微小的差别:使用FFMPEG类库分离出多媒体文件中的H.264码流
因此在使用FFMPEG进行视音频处理的时候,常常可以将得到的AVPacket的data数据直接写成文件,从而得到视音频的码流文件。【如果.h264码流文件不能直接播放,参考上述使用FFMPEG类库分离出多媒体文件中的H.264码流】
博客地址:https://blog.csdn.net/leixiaohua1020/article/details/11800877
雷神这篇文章的意思是说,在裸流前面需要sps和pps信息,否则解码器无法解码。另外每个nalu的头部需要替换为标准头部0001【每个nalu之间的分隔符】
代码验证:
分离signtl.ts文件中的h.264码流:
#include
#include
int main(int argc, char *argv[]) {
av_register_all();
AVFormatContext *formatCtx = NULL;
int videoStreamIndex = -1;
// 打开多媒体文件
if (avformat_open_input(&formatCtx, "E:\\BDWP\\小学期课程资料 - 基于FFmpeg+SDL的视频播放器的制作\\工具\\testvideo\\sintel.ts", NULL, NULL) != 0) {
fprintf(stderr, "无法打开文件\n");
return -1;
}
// 查找视频流
if (avformat_find_stream_info(formatCtx, NULL) < 0) {
fprintf(stderr, "无法获取流信息\n");
return -1;
}
// 寻找视频流
for (int i = 0; i < formatCtx->nb_streams; i++) {
if (formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
formatCtx->streams[i]->codec->codec_id == AV_CODEC_ID_H264) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
fprintf(stderr, "未找到 H.264 视频流\n");
return -1;
}
FILE *outputFile = fopen("output.h264", "wb");
if (!outputFile) {
fprintf(stderr, "无法打开输出文件\n");
return -1;
}
// 解复用 H.264 视频流
AVPacket packet;
av_init_packet(&packet);
//wgj 写入sps和pps
//unsigned char *dummy = NULL; //输入的指针
//int dummy_len;
//AVBitStreamFilterContext* bsfc = av_bitstream_filter_init("h264_mp4toannexb");
//av_bitstream_filter_filter(bsfc, formatCtx->streams[videoStreamIndex]->codec, NULL, &dummy, &dummy_len, NULL, 0, 0);
//fwrite(formatCtx->streams[videoStreamIndex]->codec->extradata, formatCtx->streams[videoStreamIndex]->codec->extradata_size, 1, outputFile);
//av_bitstream_filter_close(bsfc);
//free(dummy);
//
while (av_read_frame(formatCtx, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
// 在这里处理 H.264 码流,packet.data 中存储着视频帧数据
// 你可以将数据存储到文件、进行解码、进行其他处理等操作
fwrite(packet.data, 1, packet.size, outputFile);
//wgj
/*char nal_start[] = { 0,0,0,1 };
fwrite(nal_start, 4, 1, outputFile);
fwrite(packet.data + 4, packet.size - 4, 1, outputFile);*/
//
}
av_packet_unref(&packet);
}
avformat_close_input(&formatCtx);
return 0;
}
运行结果:
.ts分离的.h264文件可以在potplayer中播放,
但是不能在vlc中播放,可能的原因不明
.mp4文件分离的.h264文件肯定不能直接播放
#include
#include
int main(int argc, char *argv[]) {
av_register_all();
AVFormatContext *formatCtx = NULL;
int videoStreamIndex = -1;
// 打开多媒体文件
if (avformat_open_input(&formatCtx, "E:\\KwDownload\\song\\王菲-匆匆那年.mp4", NULL, NULL) != 0) {
fprintf(stderr, "无法打开文件\n");
return -1;
}
// 查找视频流
if (avformat_find_stream_info(formatCtx, NULL) < 0) {
fprintf(stderr, "无法获取流信息\n");
return -1;
}
// 寻找视频流
for (int i = 0; i < formatCtx->nb_streams; i++) {
if (formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
formatCtx->streams[i]->codec->codec_id == AV_CODEC_ID_H264) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
fprintf(stderr, "未找到 H.264 视频流\n");
return -1;
}
FILE *outputFile = fopen("output.h264", "wb");
if (!outputFile) {
fprintf(stderr, "无法打开输出文件\n");
return -1;
}
// 解复用 H.264 视频流
AVPacket packet;
av_init_packet(&packet);
//wgj 写入sps和pps
//这段代码的主要目的是使用 FFmpeg 的比特流过滤器将 H.264 的 MP4 格式数据转换为 Annex B 格式,然后将转换后的数据的额外信息(extradata)写入文件,
unsigned char *dummy = NULL; //输入的指针
int dummy_len;
AVBitStreamFilterContext* bsfc = av_bitstream_filter_init("h264_mp4toannexb");
av_bitstream_filter_filter(bsfc, formatCtx->streams[videoStreamIndex]->codec, NULL, &dummy, &dummy_len, NULL, 0, 0);//此处对formatCtx->streams[videoStreamIndex]->codec->extradata进行了赋值
fwrite(formatCtx->streams[videoStreamIndex]->codec->extradata, formatCtx->streams[videoStreamIndex]->codec->extradata_size, 1, outputFile);
av_bitstream_filter_close(bsfc);
free(dummy);
while (av_read_frame(formatCtx, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
// 在这里处理 H.264 码流,packet.data 中存储着视频帧数据
// 你可以将数据存储到文件、进行解码、进行其他处理等操作
//fwrite(packet.data, 1, packet.size, outputFile);
//wgj 第二步
char nal_start[] = { 0,0,0,1 };
fwrite(nal_start, 4, 1, outputFile);
fwrite(packet.data + 4, packet.size - 4, 1, outputFile);
//
}
av_packet_unref(&packet);
}
avformat_close_input(&formatCtx);
return 0;
}
运行结果:
.mp4文件分离的.h264文件可以用potplayer进行播放了