读取本地文件(网络流)信息
#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/rtsp1if (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绑定到AVFormatContextpAVFmtCtx->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) // 0return 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 bytesavio_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);
}