FFMPEG结构体分析:AVPacket

AVPacket是存储压缩编码数据相关信息的结构体

例如对于H.264来说。1个AVPacket的data通常对应一个NAL。【注意:此处强调是“通常”,不是“所有”】

注意:在这里只是对应,而不是一模一样。他们之间有微小的差别:使用FFMPEG类库分离出多媒体文件中的H.264码流

因此在使用FFMPEG进行视音频处理的时候,常常可以将得到的AVPacket的data数据直接写成文件,从而得到视音频的码流文件。【如果.h264码流文件不能直接播放,参考上述使用FFMPEG类库分离出多媒体文件中的H.264码流】

涉及到的知识点:使用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文件肯定不能直接播放

加入作者的2点以后 代码:


#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进行播放了

你可能感兴趣的:(ffmpeg)