FFmpeg【SDK02】关于AVIO的一些使用

本文详细介绍了如何在C++中使用FFmpeg库处理本地文件和网络流(如RTSP),包括使用AVFormatContext打开和解析文件,自定义AVIO进行读取和定位,以及处理自定义数据源获取视频文件信息。
摘要由CSDN通过智能技术生成

 读取本地文件(网络流)信息

#include <iostream>
#include <stdio.h>


extern "C"
{
#include <libavformat\avformat.h>
#include <libavutil\avutil.h>
#include <libavutil\log.h>
#include <libavformat\avio.h>
#include <libavutil\file.h>
#include <libavcodec\avcodec.h>
#include <libavutil\error.h>
}

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

// 1. 读取本地文件 和 网络流(rtsp)
void readLoadHostFile()
{
	// av_register_all();		// ffmpeg4.0 版本后被抛弃
	avformat_network_init();	// 使用网络流时需要添加
	
	AVFormatContext* pAVFmtCtx = NULL;
	AVInputFormat*   pAVInputFmt = NULL;

	pAVFmtCtx = avformat_alloc_context();		// 申请AVFormatContext内存

	// 打开文件流或网络流
	// No1. 本地文件流		input_5s.mp4
	// No2. VLC推rtsp流		rtsp://:8554/rtsp1	rtsp://localhost:8554/rtsp1
	if (avformat_open_input(&pAVFmtCtx, "input_5s.mp4", pAVInputFmt, NULL))
	{
		av_log(pAVFmtCtx, AV_LOG_WARNING, "open file/networkStream faild!\n");
		avformat_free_context(pAVFmtCtx);		// 释放AVFormatContext内存
		avformat_network_deinit();
		return;
	}
	av_log(pAVFmtCtx, AV_LOG_INFO, "open file/networkStream success!\n");
	
	// 查找流信息
	if (avformat_find_stream_info(pAVFmtCtx, NULL) < 0)
	{
		av_log(pAVFmtCtx, AV_LOG_WARNING, "find stream info faild!\n");	
		avformat_close_input(&pAVFmtCtx); 
		avformat_free_context(pAVFmtCtx);		
		avformat_network_deinit();
		return;
	}
	av_log(pAVFmtCtx, AV_LOG_INFO, "find stream info success!\n");

	// 打印流的个数
	av_log(pAVFmtCtx, AV_LOG_INFO, "nbstream: %d\n", pAVFmtCtx->nb_streams);

	avformat_close_input(&pAVFmtCtx);			// 先关闭再释放
	avformat_free_context(pAVFmtCtx);		
	avformat_network_deinit();
}

 使AVIO获取视频文件信息

// 2. 自定义AVIO
// 读回调(返回读取的字节数)
int read_callback(void *opaque, uint8_t *buf, int buf_size)
{
	FILE* fp = (FILE*)opaque;
	size_t size = fread(buf, sizeof(uint8_t), buf_size, fp);
	printf("Read Bytes: %d\n", size);
	return (int)size;
}

// 返回seek到的位置
int64_t seek_callback(void *opaque, int64_t offset, int whence)
{
	FILE *fp = (FILE*)opaque;
	if (whence == AVSEEK_SIZE) 
	{
		return -1;
	}
	fseek(fp, offset, whence);
	return ftell(fp);
}

void selfDefAVIO()
{
	AVFormatContext* pAVFmtCtx = NULL;
	AVInputFormat*   pAVInputFmt = NULL;

	pAVFmtCtx = avformat_alloc_context();

	FILE* fp = fopen("input_5s.mp4", "rb");
	int nBuffSize = 1024;
	// unsigned char* buffer = (unsigned char*)malloc(nBuffSize);	// 此处使用malloc会中断
	uint8_t* buffer = (uint8_t*)av_malloc(nBuffSize);

	AVIOContext* pAVIOCtx = avio_alloc_context(buffer, 
											   nBuffSize, 
											   0,
											   fp,				// 文件指针
											   read_callback,	// 读回调
											   0,				// 写回调
											   seek_callback);	// 定位回调

	if (NULL == pAVIOCtx)
	{
		av_log(NULL, AV_LOG_WARNING, "AVIOContext alloc faild!\n");
		av_free(pAVIOCtx);
		return;
	}
											   
	pAVFmtCtx->pb = pAVIOCtx;					// 将AVIOContext绑定到AVFormatContext
	pAVFmtCtx->flags = AVFMT_FLAG_CUSTOM_IO;	// 告诉ffmpeg自己创建AVIOContext(不需要它再创建)

	// 打开流
	if (avformat_open_input(&pAVFmtCtx, "", pAVInputFmt, NULL) < 0)
	{
		av_log(pAVFmtCtx, AV_LOG_WARNING, "open file stream faild!\n");
		av_free(pAVIOCtx);
		avformat_free_context(pAVFmtCtx);		// 释放AVFormatContext内存
		return;
	}
	av_log(pAVFmtCtx, AV_LOG_INFO, "open file stream success!\n");
	// 进一步读取流信息(为 pFormatCtx->streams 填充上正确的信息)
	if (avformat_find_stream_info(pAVFmtCtx, NULL) < 0)
	{
		av_log(pAVFmtCtx, AV_LOG_WARNING, "find stream info faild!\n");
		avformat_close_input(&pAVFmtCtx);
		av_free(pAVIOCtx);
		avformat_free_context(pAVFmtCtx);	
		return;
	}
	av_log(pAVFmtCtx, AV_LOG_INFO, "find stream info success!\n");
	// 打印流的个数
	av_log(pAVFmtCtx, AV_LOG_INFO, " nbstream: %d\n", pAVFmtCtx->nb_streams);

	avformat_close_input(&pAVFmtCtx);
	av_free(pAVIOCtx);
	avformat_free_context(pAVFmtCtx);
}

 使用AVIO和自定义数据类型获取视频文件信息

// 3. 自定义数据来源(可以是文件,内存,网络流)
struct buffer_data	// 自定义缓冲区
{
	uint8_t *ptr;
	size_t size;	// size left in the buffer
};

//读取数据(回调函数)
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
	struct buffer_data *bd = (struct buffer_data*)opaque;
	buf_size = FFMIN(buf_size, bd->size);

	if (!buf_size)			// 0
		return AVERROR_EOF;
	printf("ptr:%p size:%d\n", bd->ptr, bd->size);

	/// 灵活应用[内存buf]:读取的是内存,例如:加密播放器,这里解密
	memcpy(buf, bd->ptr, buf_size);
	bd->ptr += buf_size;
	bd->size -= buf_size;

	return buf_size;
}

void selfDefDataSrc()
{
	struct buffer_data bd = { 0 };
	// 1. 将文件映射到内存上
	int nRet = av_file_map("input_5s.mp4", &bd.ptr, &bd.size, 0, NULL);
	if (nRet < 0)
	{
		av_log(NULL, AV_LOG_ERROR, "map file to memory faild!\n");
		return;
	}
	av_log(NULL, AV_LOG_INFO, "map file to memory success!\n");

	// 2. 创建AVFormatContext对象
	AVFormatContext* pAVFmtCtx = NULL;
	pAVFmtCtx = avformat_alloc_context();
	if (NULL == pAVFmtCtx)
	{
		av_log(NULL, AV_LOG_ERROR, "create AVFormatContext faild!\n");
		av_file_unmap(bd.ptr, bd.size);	// 内存映射文件:解绑定
		return;
	}
	av_log(NULL, AV_LOG_INFO, "create AVFormatContext success!\n");

	// 3. 为avio buffer分配内存
	uint8_t* avio_ctx_buffer = NULL;
	size_t avio_ctx_buffer_size = 4096;				// 回调每次读取 4096 bytes
	avio_ctx_buffer = (uint8_t*)av_malloc(avio_ctx_buffer_size);
	if (!avio_ctx_buffer) 
	{
		av_log(NULL, AV_LOG_ERROR, "av_malloc avio_ctx_buffer faild!\n");
		avformat_free_context(pAVFmtCtx);
		av_file_unmap(bd.ptr, bd.size);
		return;
	}
	av_log(NULL, AV_LOG_INFO, "av_malloc avio_ctx_buffer success!\n");

	AVIOContext* avio_ctx = avio_alloc_context(
		avio_ctx_buffer, 
		avio_ctx_buffer_size,
		0,
		&bd,					// 从bd里面读数据
		&read_packet,			
		NULL,
		NULL);
	if (!avio_ctx) 
	{
		av_log(NULL, AV_LOG_ERROR, "avio_alloc_context AVIOContext faild!\n");
		av_freep(avio_ctx_buffer);
		avformat_free_context(pAVFmtCtx);
		av_file_unmap(bd.ptr, bd.size);
		return;
	}
	pAVFmtCtx->pb = avio_ctx;
	av_log(NULL, AV_LOG_INFO, "avio_alloc_context AVIOContext success!\n");

	nRet = avformat_open_input(&pAVFmtCtx, NULL, NULL, NULL);
	if (nRet)
	{
		av_log(NULL, AV_LOG_ERROR, "avformat_open_input faild!\n");
		avio_context_free(&avio_ctx);
		av_freep(avio_ctx_buffer);
		avformat_free_context(pAVFmtCtx);
		av_file_unmap(bd.ptr, bd.size);
		return;
	}
	av_log(NULL, AV_LOG_INFO, "avformat_open_input success!\n");

	// 查找流信息
	nRet = avformat_find_stream_info(pAVFmtCtx, NULL);
	if (nRet < 0) 
	{
		av_log(NULL, AV_LOG_ERROR, "avformat_find_stream_info faild!\n");
		avformat_close_input(&pAVFmtCtx);
		avio_context_free(&avio_ctx);
		av_freep(avio_ctx_buffer);
		avformat_free_context(pAVFmtCtx);
		av_file_unmap(bd.ptr, bd.size);
		return;
	}
	av_log(NULL, AV_LOG_INFO, "avformat_find_stream_info success!\n");
	printf(" 》》》nb_streams=%d\n", pAVFmtCtx->nb_streams);

	av_dump_format(pAVFmtCtx, 0, "input_5s.mp4", 0);

	// 关闭释放资源
	avformat_close_input(&pAVFmtCtx);
	if (avio_ctx)
		av_freep(&avio_ctx->buffer);
	avio_context_free(&avio_ctx);
	av_file_unmap(bd.ptr, bd.size);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

石小浪♪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值