FFmpeg音视频入门-使用FFmpeg读取多媒体文件的信息C++代码实现+详解
生活随笔
收集整理的這篇文章主要介紹了
FFmpeg音视频入门-使用FFmpeg读取多媒体文件的信息C++代码实现+详解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
讀取音視頻信息
設置日志等級
// 設置日志等級 av_log_set_level(AV_LOG_DEBUG);參數檢查
必須給出要讀取的多媒體文件路徑才能進行接下來的多媒體讀取的任務。
if (argc != 2) {cout << "please input a reading file" << "argc = " << argc << endl;return -1; } char *inputFileName = argv[1];將多媒體文件映射為內存
// 將文件進行內存映射 /** mmap() creates a new mapping in the virtual address space of the calling process. The starting address for the new mapping is specified in addr. The length argument specifies the length ofthe mapping (which must be greater than 0).If addr is NULL, then the kernel chooses the (page-aligned) address at which to create the mapping; this is the most portable method of creating a new mapping. If addr is not NULL, then thekernel takes it as a hint about where to place the mapping; on Linux, the kernel will pick a nearby page boundary (but always above or equal to the value specified by/proc/sys/vm/mmap_min_addr) and attempt to create the mapping there. If another mapping already exists there, the kernel picks a new address that may or may not depend on the hint. The ad‐dress of the new mapping is returned as the result of the call.* */ uint8_t *buffer = nullptr; size_t buffer_size = 0; int ret = av_file_map(inputFileName, &buffer, &buffer_size, 0, nullptr); if (ret < 0) {cout << "av_file_map failed" << "ret = " << ret << endl;goto end; }// 記錄 @av_file_map 中獲取的文件內存映射的內容和長度 bufferData.ptr = buffer; bufferData.size = buffer_size;在FFmpeg中,linux主機上av_file_map是通過mmap實現的,也就是將文件映射到一段內存上,接下來直接操作內存地址就可以實現對文件的操作,具體的可以參考mmap函數的使用,這里也只是對mmap函數進行了一些封裝。
linux主機上av_file_map的實現主要函數如下:
ptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (ptr == MAP_FAILED) {err = AVERROR(errno);av_strerror(err, errbuf, sizeof(errbuf));av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", errbuf);close(fd);*size = 0;return err; } *bufptr = ptr;初始化AVFormatContext結構體
在使用ffmpeg進行編解碼時,AVFormatContext將貫穿全文。
// Allocate an AVFormatContext. pFmtCtx = avformat_alloc_context(); if (!pFmtCtx) {ret = AVERROR(ENOMEM);goto end; }因為是多多媒體文件的信息的讀取,因此,接下來需要使用avformat_open_input打開文件的內容
// 調用 avformat_open_input 之前,要是使用文件的音視頻處理,這里需要提前進行初始化,然后再調用、 // avformat_open_input 打開對應的文件 pFmtCtx->pb = pAvioCtx; ret = avformat_open_input(&pFmtCtx, nullptr, nullptr, nullptr); if (ret < 0) {cerr << "Could not open input!" << endl;goto end; }然后再調用avformat_find_stream_info查詢當前楨的信息
Read packets of a media file to get stream information.
ret = avformat_find_stream_info(pFmtCtx, nullptr); if (ret < 0) {cerr << "Could not find stream information!" << endl;goto end; }輸出楨信息
如果文件中有楨信息,則可以使用av_dump_format函數視頻文件的信息打印出來
av_dump_format(pFmtCtx, 0, inputFileName, 0);資源釋放
end:avformat_close_input(&pFmtCtx);if (pAvioCtxBuffer && !pAvioCtx)av_freep(pAvioCtxBuffer);if (pAvioCtx)av_freep(&pAvioCtx->buffer);avio_context_free(&pAvioCtx);av_file_unmap(buffer, buffer_size);完整代碼實現
// // Created by andrew on 2020/12/13. // //#include <iostream>extern "C" { #include <libavformat/avformat.h> #include <libavutil/log.h> #include <libavcodec/avcodec.h> #include <libavformat/avio.h> #include <libavutil/file.h> #include <cstdio> }using namespace std;// 為mmap buffer定義一個結構體指針用戶管理數據 struct buffer_data {uint8_t *ptr;size_t size; // size left in the buffer };static int ReadPacket(void *pOpaque, uint8_t *pBuff, int bufferSize) {auto *bd = (struct buffer_data *) pOpaque; // #define FFMIN(a,b) ((a) > (b) ? (b) : (a))bufferSize = FFMIN(bufferSize, bd->size);if (!bufferSize) {cout << "ptr = " << bd->ptr << "size = " << bd->size << endl;} // 將音視頻數據內部的data復制到buff中memcpy(pBuff, bd->ptr, bufferSize);bd->ptr += bufferSize;bd->size -= bufferSize;return bufferSize; }int main(int argc, char *argv[]) {AVIOContext *pAvioCtx = nullptr;uint8_t *pAvioCtxBuffer = nullptr;size_t avioCtxBufferSize = 4096;struct buffer_data bufferData = {nullptr, 0};// 貫穿全局的context信息AVFormatContext *pFmtCtx = nullptr;// 設置日志等級av_log_set_level(AV_LOG_DEBUG);if (argc != 2) {cout << "please input a reading file" << "argc = " << argc << endl;return -1;}char *inputFileName = argv[1];// 將文件進行內存映射/** mmap() creates a new mapping in the virtual address space of the calling process. The starting address for the new mapping is specified in addr. The length argument specifies the length ofthe mapping (which must be greater than 0).If addr is NULL, then the kernel chooses the (page-aligned) address at which to create the mapping; this is the most portable method of creating a new mapping. If addr is not NULL, then thekernel takes it as a hint about where to place the mapping; on Linux, the kernel will pick a nearby page boundary (but always above or equal to the value specified by/proc/sys/vm/mmap_min_addr) and attempt to create the mapping there. If another mapping already exists there, the kernel picks a new address that may or may not depend on the hint. The ad‐dress of the new mapping is returned as the result of the call.* */uint8_t *buffer = nullptr;size_t buffer_size = 0;int ret = av_file_map(inputFileName, &buffer, &buffer_size, 0, nullptr);if (ret < 0) {cout << "av_file_map failed" << "ret = " << ret << endl;goto end;}// 記錄 @av_file_map 中獲取的文件內存映射的內容和長度bufferData.ptr = buffer;bufferData.size = buffer_size;// Allocate an AVFormatContext.pFmtCtx = avformat_alloc_context();if (!pFmtCtx) {ret = AVERROR(ENOMEM);goto end;}pAvioCtxBuffer = (uint8_t *) av_malloc(avioCtxBufferSize);if (!pAvioCtxBuffer) {ret = AVERROR(ENOMEM);goto end;}pAvioCtx = avio_alloc_context(pAvioCtxBuffer, avioCtxBufferSize, 0, &bufferData, &ReadPacket,nullptr, nullptr);if (!pAvioCtx) {ret = AVERROR(ENOMEM);goto end;}// 調用 avformat_open_input 之前,要是使用文件的音視頻處理,這里需要提前進行初始化,然后再調用、// avformat_open_input 打開對應的文件pFmtCtx->pb = pAvioCtx;ret = avformat_open_input(&pFmtCtx, nullptr, nullptr, nullptr);if (ret < 0) {cerr << "Could not open input!" << endl;goto end;}ret = avformat_find_stream_info(pFmtCtx, nullptr);if (ret < 0) {cerr << "Could not find stream information!" << endl;goto end;}av_dump_format(pFmtCtx, 0, inputFileName, 0);cout << "avio reading demo success" << endl; end:avformat_close_input(&pFmtCtx);if (pAvioCtxBuffer && !pAvioCtx)av_freep(pAvioCtxBuffer);if (pAvioCtx)av_freep(&pAvioCtx->buffer);avio_context_free(&pAvioCtx);av_file_unmap(buffer, buffer_size);return 0; }總結
以上是生活随笔為你收集整理的FFmpeg音视频入门-使用FFmpeg读取多媒体文件的信息C++代码实现+详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【计算机科学基础】透明性
- 下一篇: 作者:刘诗凯(1983-),男,华为大数