音视频 ffmpeg库使用
程序员文章站
2022-03-04 23:41:59
...
ffmpeg 4.2.4
源代码
extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/error.h"
#include "libavutil/rational.h"
}
#include <iostream>
#include <fstream>
#include <cassert>
#include <cstring>
#include <csignal>
bool g_bStop = false;
void on_ctrl_c(int )
{
g_bStop = true;
}
void list_demuxer()
{
void* opaque = nullptr;
const AVInputFormat* pIFormat = av_demuxer_iterate(&opaque);
while (pIFormat != nullptr)
{
std::cout << "" << pIFormat->name << std::endl;
pIFormat = av_demuxer_iterate(&opaque);
}
}
void read_file(const char* szFilename)
{
do
{
std::fstream fs;
fs.open(szFilename, std::fstream::in | std::fstream::binary);
if (!fs.is_open())
{
std::cout << "open file failed" << std::endl;
break;
}
char buffer[1024] = "";
for (int i = 0;; i++)
{
fs.read(buffer, 1024);
auto iReadLength = fs.gcount();
if(fs.eof()) break;
}
fs.close();
} while (false);
}
// Entry
int main(int argc, char** argv)
{
int iRet = 0;
std::cout << "Start ." << std::endl;
signal(SIGINT, &on_ctrl_c);
#if 0
list_demuxer();
read_file("normal.h264");
#endif
std::string szMediaFilename = argc > 1 ? argv[1] : "normal.mp4";
std::string szPrefixMediaFilename = szMediaFilename.substr(0, szMediaFilename.rfind('.'));
char szErrorBuffer[AV_ERROR_MAX_STRING_SIZE] = "";
AVFormatContext* pMediaFormatCtx = nullptr;
do
{
// AVFormatContext
iRet = avformat_open_input(&pMediaFormatCtx, szMediaFilename.c_str(), 0, 0);
if(iRet != 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "avformat_open_input failed " << szErrorBuffer << std::endl;
break;
}
iRet = avformat_find_stream_info(pMediaFormatCtx, 0);
if (iRet != 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "avformat_find_stream_info failed " << szErrorBuffer << std::endl;
break;
}
// AVStream
AVStream* pVideoStream = nullptr,* pAudioStream = nullptr;
for (unsigned int i = 0; i < pMediaFormatCtx->nb_streams; i++)
{
if (pMediaFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
pVideoStream = pMediaFormatCtx->streams[i];
}
if (pMediaFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
pAudioStream = pMediaFormatCtx->streams[i];
}
}
if (pVideoStream == nullptr)
{
std::cout << "pVideoStream empty " << std::endl;
break;
}
if (pAudioStream == nullptr)
{
std::cout << "pAudioStream empty " << std::endl;
break;
}
// AVCodecContext
AVCodec* pVideoCodec = avcodec_find_decoder(pVideoStream->codecpar->codec_id);
if (pVideoCodec == nullptr)
{
std::cout << "avcodec_find_decoder failed " << std::endl;
break;
}
AVCodecContext* pVideoCodecCtx = avcodec_alloc_context3(pVideoCodec);
if (pVideoCodecCtx == nullptr)
{
std::cout << "avcodec_alloc_context3 failed " << std::endl;
break;
}
iRet = avcodec_parameters_to_context(pVideoCodecCtx, pVideoStream->codecpar);
if (iRet < 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "avcodec_parameters_to_context failed " << szErrorBuffer << std::endl;
break;
}
AVCodec* pAudioCodec = avcodec_find_decoder(pAudioStream->codecpar->codec_id);
if (pAudioCodec == nullptr)
{
std::cout << "avcodec_find_decoder failed " << std::endl;
break;
}
AVCodecContext* pAudioCodecCtx = avcodec_alloc_context3(pAudioCodec);
if (pAudioCodecCtx == nullptr)
{
std::cout << "avcodec_alloc_context3 failed " << std::endl;
break;
}
iRet = avcodec_parameters_to_context(pAudioCodecCtx, pAudioStream->codecpar);
if (iRet < 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "avcodec_parameters_to_context failed " << szErrorBuffer << std::endl;
break;
}
// open decoder
iRet = avcodec_open2(pVideoCodecCtx, pVideoCodec, nullptr);
if(iRet != 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "avcodec_open2 failed " << szErrorBuffer << std::endl;
}
iRet = avcodec_open2(pAudioCodecCtx, pAudioCodec, nullptr);
if (iRet != 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "avcodec_open2 failed " << szErrorBuffer << std::endl;
}
// decode
AVPacket sMediapacket;
AVFrame* pMediaFrame = av_frame_alloc();
std::fstream videostream, audiostream;
std::fstream videobigstream, audiobigstream;
do
{
iRet = av_read_frame(pMediaFormatCtx, &sMediapacket);
if (iRet < 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "av_read_frame failed " << szErrorBuffer << std::endl;
break;
}
if (sMediapacket.pts < 0)
{
std::cout << "avpacket pts: " << sMediapacket.pts << std::endl;
continue;
}
// video decode
if (sMediapacket.stream_index == pVideoStream->index)
{
iRet = avcodec_send_packet(pVideoCodecCtx, &sMediapacket);
if (iRet != 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "warning avcodec_send_packet failed " << szErrorBuffer << std::endl;
break;
}
iRet = avcodec_receive_frame(pVideoCodecCtx, pMediaFrame);
if (iRet != 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "warning avcodec_receive_frame failed " << szErrorBuffer << std::endl;
break;
}
// write h264 stream
if(pVideoCodecCtx->codec_id == AV_CODEC_ID_H264)
{
char szStart3Code[3] = { 0x00,0x00, 0x01 };
char szStart4Code[4] = { 0x00,0x00, 0x00, 0x01 };
if (!videostream.is_open())
{
videostream.open((szPrefixMediaFilename + ".h264").c_str(), std::fstream::out | std::fstream::binary);
}
assert(videostream.is_open());
videostream.seekg(0, std::fstream::end);
int iFileLength = (int)videostream.tellg();
videostream.seekg(0, std::fstream::cur);
// 0x67 SPS - 0x68 PPS nal unit
if (iFileLength == 0)
{
unsigned short u16SpsLength = (((unsigned short)pVideoCodecCtx->extradata[6]) << 8) + pVideoCodecCtx->extradata[7];
unsigned short u16PpsLength = (((unsigned short)pVideoCodecCtx->extradata[8 + u16SpsLength + 1]) << 8) + pVideoCodecCtx->extradata[9 + u16SpsLength + 1];
char* szSps = (char*)malloc(u16SpsLength);
char* szPps = (char*)malloc(u16PpsLength);
memcpy(szSps, (void*)&pVideoCodecCtx->extradata[6+2], u16SpsLength);
memcpy(szPps, (void*)&pVideoCodecCtx->extradata[6 + 2 + u16SpsLength + 1 + 2], u16PpsLength);
videostream.write(szStart4Code, 4);
videostream.write(szSps, u16SpsLength);
videostream.write(szStart4Code, 4);
videostream.write(szPps, u16PpsLength);
free(szSps);
free(szPps);
}
// other nal unit
for (int i = 0, iStep = 0; i < sMediapacket.size; i += iStep)
{
uint32_t iUnitSize = ((uint32_t)sMediapacket.data[i] << 24) + ((uint32_t)sMediapacket.data[i + 1] << 16) +
((uint32_t)sMediapacket.data[i + 2] << 8) + (uint32_t)sMediapacket.data[i + 3];
iStep = iUnitSize + 4;
sMediapacket.data[i] = sMediapacket.data[i + 1] = sMediapacket.data[i + 2] = 0x00;
sMediapacket.data[i + 3] = 0x01;
videostream.write((char*)&sMediapacket.data[i], (std::streamsize)iStep);
std::cout << "write to file : pts " << sMediapacket.pts * av_q2d(pVideoStream->time_base) << " size " << iStep << std::endl;
}
}
}
// audio decode
if (sMediapacket.stream_index == pAudioStream->index)
{
iRet = avcodec_send_packet(pAudioCodecCtx, &sMediapacket);
if (iRet != 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "warning avcodec_send_packet failed " << szErrorBuffer << std::endl;
break;
}
iRet = avcodec_receive_frame(pAudioCodecCtx, pMediaFrame);
if (iRet != 0)
{
av_strerror(iRet, szErrorBuffer, AV_ERROR_MAX_STRING_SIZE);
std::cout << "warning avcodec_receive_frame failed " << szErrorBuffer << std::endl;
break;
}
// write aac stream
if (pAudioCodecCtx->codec_id == AV_CODEC_ID_AAC)
{
if (!audiostream.is_open())
{
audiostream.open((szPrefixMediaFilename + ".aac").c_str(), std::fstream::out | std::fstream::binary);
}
assert(audiostream.is_open());
int rates[] = { 96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350,-1,-1,-1 };
int iProfile = pAudioStream->codecpar->profile;
int iChannel = pAudioStream->codecpar->channels;
int iSamplerate = pAudioStream->codecpar->sample_rate;
int iSamplerateIndex = 0;
for (auto rate : rates)
{
if(iSamplerate == rate) break;
iSamplerateIndex++;
}
int iAdtsLength = 7;
char* pAdts = (char*)malloc(iAdtsLength * sizeof(char));
int iSize = sMediapacket.size + iAdtsLength;
pAdts[0] = (char)0xff;
pAdts[1] = (char)0xf1;
pAdts[2] = (((iProfile - 1) << 6) + (iSamplerateIndex << 2) + (iChannel >> 2));
pAdts[3] = (((iChannel & 3) << 6) + (iSize >> 11));
pAdts[4] = ((iSize & 0x7ff) >> 3);;
pAdts[5] = (((iSize & 7) << 5) + 0x1f);
pAdts[6] = (char)0xfc;
audiostream.write(pAdts, (std::streamsize)iAdtsLength);
audiostream.write((char*)sMediapacket.data, (std::streamsize)sMediapacket.size);
free(pAdts);
}
// write pcm stream
if(false)
{
if (!audiobigstream.is_open())
{
audiobigstream.open((szPrefixMediaFilename + ".pcm").c_str(), std::fstream::out | std::fstream::binary);
}
assert(audiobigstream.is_open());
int iChannel = pAudioStream->codecpar->channels;
audiobigstream.write((char*)&pMediaFrame->data[0], (std::streamsize)pMediaFrame->linesize[0] / iChannel);
//std::cout << "write to file : pts " << sMediapacket.pts * av_q2d(pAudioStream->time_base) << " size " << sMediapacket.size << std::endl;
}
}
av_packet_unref(&sMediapacket);
} while (!g_bStop);
if (videostream.is_open())
{
videostream.close();
}
if (audiostream.is_open())
{
audiostream.close();
}
if (audiobigstream.is_open())
{
audiobigstream.close();
}
av_frame_free(&pMediaFrame);
av_packet_unref(&sMediapacket);
// close decoder
avcodec_close(pAudioCodecCtx);
avcodec_close(pVideoCodecCtx);
// AVCodecContext
avcodec_free_context(&pAudioCodecCtx);
pAudioCodecCtx = nullptr;
avcodec_free_context(&pVideoCodecCtx);
pVideoCodecCtx = nullptr;
// AVFormatContext
avformat_close_input(&pMediaFormatCtx);
pMediaFormatCtx = nullptr;
}while(false);
std::cout << "End ." << std::endl;
return iRet;
}
windows build
@echo off
pushd "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\Tools\"
call VsDevCmd.bat -arch=amd64
popd
cl /c /I. /Iffmpeg\include /DWIN32 /W3 /WX- /GS /GR /Zi /Od /MDd /EHsc /nologo main.cpp
link main.obj /LIBPATH:. /LIBPATH:.\ffmpeg\lib /DYNAMICBASE avformat.lib avcodec.lib avutil.lib /DEBUG /MACHINE:X64 /SUBSYSTEM:CONSOLE /PDB:main.pdb /OUT:main.exe
pause
上一篇: 天地图逆地理解析 搜索名称获取相应坐标系
下一篇: Rtsp支持Scale的抓包