从mp4、flv、ts文件中提取出AVC(h264)

分别从封装格式为mp4、flv、ts文件中提取出AVC(h264)并写入文件

/*****************************************************************//**
 * \file   WriteAVC.cpp
 * \brief  提取视频中的视频流,写入为AVC(h264)文件
 * 
 * \author 13648
 * \date   April 2024
 *********************************************************************/
#define _CRT_SECURE_NO_WARNINGS
#include "myLog.h"
#include <iostream>

extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavcodec/bsf.h>
}

#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avcodec.lib")

/**
 * 由于h264有两种格式,一种mp4格式(不带startcode,sps,pps信息)一种annexb格式(带startcode,sps、pps信息)
 * 但是大多数的编解码器只支持annexb格式pkt数据,
 * 因此在处理mp4或者flv格式的文件时需要使用h264_mp4toannexb比特流过滤器处理
 */
int main()
{
	AVFormatContext* ifmt_ctx = NULL;
	const std::string in_filename = "./MediaFile/input_5s.flv";		// input_5s.flv input_5s.ts

	int nRet = avformat_open_input(&ifmt_ctx, in_filename.c_str(), NULL, NULL);
	if (nRet != 0)
	{
		LOG_WARNING("avformat_open_input error\n");
		return -1;
	}

	nRet = avformat_find_stream_info(ifmt_ctx, NULL);
	if (nRet < 0)
	{
		LOG_WARNING("avformat_find_stream_info faild\n");
		avformat_close_input(&ifmt_ctx);
		return -2;
	}

	int video_idx = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
	if (video_idx < 0)
	{
		LOG_WARNING("avformat_find_stream_info faild\n");
		avformat_close_input(&ifmt_ctx);
		return -3;
	}

	const std::string out_filename = "./MediaFile/input_5s.h264";
	FILE* out_fp = fopen(out_filename.c_str(), "wb");
	if (!out_fp)
	{
		LOG_WARNING("open out_filename faild\n");
		avformat_close_input(&ifmt_ctx);
		return -4;
	}

	// 获取比特流过滤器
	const AVBitStreamFilter* bsfilter = av_bsf_get_by_name("h264_mp4toannexb");
	AVBSFContext* bsf_ctx = NULL;
	// 初始化比特流过滤器
	av_bsf_alloc(bsfilter, &bsf_ctx);
	// 给过滤器上下文添加解码器属性
	avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[video_idx]->codecpar);
	av_bsf_init(bsf_ctx);

	AVPacket* pkt = av_packet_alloc();
	pkt->data = NULL;
	pkt->size = 0;
	while (true)
	{
		nRet = av_read_frame(ifmt_ctx, pkt);
		if (nRet < 0)
		{
			LOG_WARNING("av_read_frame file finish\n");
			break;
		}
		if (nRet == 0 && pkt->stream_index == video_idx)
		{
#if 1
			if (av_bsf_send_packet(bsf_ctx, pkt) != 0)	// 发送包到比特流过滤器添加startcode、sps、pps信息
			{
				av_packet_unref(pkt);
				continue;
			}
			av_packet_unref(pkt);				// 清除,下面使用这个pkt接收bsf处理后的包
			while (av_bsf_receive_packet(bsf_ctx, pkt) == 0)	// 添加sps pps后可能不止一个包
			{
				size_t writeLen = fwrite(pkt->data, 1, pkt->size, out_fp);
				if (writeLen != pkt->size)
				{
					LOG_WARNING("write pkt error\n");
				}
				fflush(out_fp);
				av_packet_unref(pkt);
			}
#else
			// 如果是ts流(自带sps pps信息,可以直接写入)
			size_t writeLen = fwrite(pkt->data, 1, pkt->size, out_fp);
			if (writeLen != pkt->size)
			{
				LOG_WARNING("fwrite pkt error\n");
			}
			av_packet_unref(pkt);
#endif
		}
		else if(nRet == 0) 
		{
			av_packet_unref(pkt);
		}
	}

	if (pkt)
	{
		av_packet_free(&pkt);
	}
	if (out_fp)
	{
		fclose(out_fp);
	}
	if (bsf_ctx)
	{
		av_bsf_free(&bsf_ctx);
	}
	if (ifmt_ctx)
	{
		avformat_close_input(&ifmt_ctx);
	}

	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

石小浪♪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值