一、 FFmpeg解复用(解封装)Demo
#include <stdio.h>
#include <libavformat/avformat.h>
int main(int argc, char **argv)
{
const char *default_filename = "believe.mp4";
char *in_filename = NULL;
if(argv[1] == NULL)
{
in_filename = default_filename;
}
else
{
in_filename = argv[1];
}
printf("in_filename = %s\n", in_filename);
AVFormatContext *ifmt_ctx = NULL;
int videoindex = -1;
int audioindex = -1;
int ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL);
if (ret < 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
printf("open %s failed:%s\n", in_filename, buf);
goto failed;
}
ret = avformat_find_stream_info(ifmt_ctx, NULL);
if (ret < 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
printf("avformat_find_stream_info %s failed:%s\n", in_filename, buf);
goto failed;
}
printf_s("\n==== av_dump_format in_filename:%s ===\n", in_filename);
av_dump_format(ifmt_ctx, 0, in_filename, 0);
printf_s("\n==== av_dump_format finish =======\n\n");
printf("media name:%s\n", ifmt_ctx->url);
printf("stream number:%d\n", ifmt_ctx->nb_streams);
printf("media average ratio:%lldkbps\n",(int64_t)(ifmt_ctx->bit_rate/1024));
int total_seconds, hour, minute, second;
total_seconds = (ifmt_ctx->duration) / AV_TIME_BASE;
hour = total_seconds / 3600;
minute = (total_seconds % 3600) / 60;
second = (total_seconds % 60);
printf("total duration: %02d:%02d:%02d\n", hour, minute, second);
printf("\n");
for (uint32_t i = 0; i < ifmt_ctx->nb_streams; i++)
{
AVStream *in_stream = ifmt_ctx->streams[i];
if (AVMEDIA_TYPE_AUDIO == in_stream->codecpar->codec_type)
{
printf("----- Audio info:\n");
printf("index:%d\n", in_stream->index);
printf("samplerate:%dHz\n", in_stream->codecpar->sample_rate);
if (AV_SAMPLE_FMT_FLTP == in_stream->codecpar->format)
{
printf("sampleformat:AV_SAMPLE_FMT_FLTP\n");
}
else if (AV_SAMPLE_FMT_S16P == in_stream->codecpar->format)
{
printf("sampleformat:AV_SAMPLE_FMT_S16P\n");
}
printf("channel number:%d\n", in_stream->codecpar->channels);
if (AV_CODEC_ID_AAC == in_stream->codecpar->codec_id)
{
printf("audio codec:AAC\n");
}
else if (AV_CODEC_ID_MP3 == in_stream->codecpar->codec_id)
{
printf("audio codec:MP3\n");
}
else
{
printf("audio codec_id:%d\n", in_stream->codecpar->codec_id);
}
if(in_stream->duration != AV_NOPTS_VALUE)
{
int duration_audio = (in_stream->duration) * av_q2d(in_stream->time_base);
printf("audio duration: %02d:%02d:%02d\n",
duration_audio / 3600, (duration_audio % 3600) / 60, (duration_audio % 60));
}
else
{
printf("audio duration unknown");
}
printf("\n");
audioindex = i;
}
else if (AVMEDIA_TYPE_VIDEO == in_stream->codecpar->codec_type)
{
printf("----- Video info:\n");
printf("index:%d\n", in_stream->index);
printf("fps:%lffps\n", av_q2d(in_stream->avg_frame_rate));
if (AV_CODEC_ID_MPEG4 == in_stream->codecpar->codec_id)
{
printf("video codec:MPEG4\n");
}
else if (AV_CODEC_ID_H264 == in_stream->codecpar->codec_id)
{
printf("video codec:H264\n");
}
else
{
printf("video codec_id:%d\n", in_stream->codecpar->codec_id);
}
printf("width:%d height:%d\n", in_stream->codecpar->width,
in_stream->codecpar->height);
if(in_stream->duration != AV_NOPTS_VALUE)
{
int duration_video = (in_stream->duration) * av_q2d(in_stream->time_base);
printf("video duration: %02d:%02d:%02d\n",
duration_video / 3600,
(duration_video % 3600) / 60,
(duration_video % 60));
}
else
{
printf("video duration unknown");
}
printf("\n");
videoindex = i;
}
}
AVPacket *pkt = av_packet_alloc();
int pkt_count = 0;
int print_max_count = 10;
printf("\n-----av_read_frame start\n");
while (1)
{
ret = av_read_frame(ifmt_ctx, pkt);
if (ret < 0)
{
printf("av_read_frame end\n");
break;
}
if(pkt_count++ < print_max_count)
{
if (pkt->stream_index == audioindex)
{
printf("audio pts: %lld\n", pkt->pts);
printf("audio dts: %lld\n", pkt->dts);
printf("audio size: %d\n", pkt->size);
printf("audio pos: %lld\n", pkt->pos);
printf("audio duration: %lf\n\n",
pkt->duration * av_q2d(ifmt_ctx->streams[audioindex]->time_base));
}
else if (pkt->stream_index == videoindex)
{
printf("video pts: %lld\n", pkt->pts);
printf("video dts: %lld\n", pkt->dts);
printf("video size: %d\n", pkt->size);
printf("video pos: %lld\n", pkt->pos);
printf("video duration: %lf\n\n",
pkt->duration * av_q2d(ifmt_ctx->streams[videoindex]->time_base));
}
else
{
printf("unknown stream_index:\n", pkt->stream_index);
}
}
av_packet_unref(pkt);
}
if(pkt)
av_packet_free(&pkt);
failed:
if(ifmt_ctx)
avformat_close_input(&ifmt_ctx);
getchar();
return 0;
}
二、读取媒体文件,将aac帧提取出到本地。
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>
#define ADTS_HEADER_LEN 7;
const int sampling_frequencies[] = {
96000,
88200,
64000,
48000,
44100,
32000,
24000,
22050,
16000,
12000,
11025,
8000
};
int adts_header(char * const p_adts_header, const int data_length,
const int profile, const int samplerate,
const int channels)
{
int sampling_frequency_index = 3;
int adtsLen = data_length + 7;
int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);
int i = 0;
for(i = 0; i < frequencies_size; i++)
{
if(sampling_frequencies[i] == samplerate)
{
sampling_frequency_index = i;
break;
}
}
if(i >= frequencies_size)
{
printf("unsupport samplerate:%d\n", samplerate);
return -1;
}
p_adts_header[0] = 0xff;
p_adts_header[1] = 0xf0;
p_adts_header[1] |= (0 << 3);
p_adts_header[1] |= (0 << 1);
p_adts_header[1] |= 1;
p_adts_header[2] = (profile)<<6;
p_adts_header[2] |= (sampling_frequency_index & 0x0f)<<2;
p_adts_header[2] |= (0 << 1);
p_adts_header[2] |= (channels & 0x04)>>2;
p_adts_header[3] = (channels & 0x03)<<6;
p_adts_header[3] |= (0 << 5);
p_adts_header[3] |= (0 << 4);
p_adts_header[3] |= (0 << 3);
p_adts_header[3] |= (0 << 2);
p_adts_header[3] |= ((adtsLen & 0x1800) >> 11);
p_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);
p_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);
p_adts_header[5] |= 0x1f;
p_adts_header[6] = 0xfc;
return 0;
}
int main(int argc, char *argv[])
{
int ret = -1;
char errors[1024];
char *in_filename = NULL;
char *aac_filename = NULL;
FILE *aac_fd = NULL;
int audio_index = -1;
int len = 0;
AVFormatContext *ifmt_ctx = NULL;
AVPacket pkt;
av_log_set_level(AV_LOG_DEBUG);
if(argc < 3)
{
av_log(NULL, AV_LOG_DEBUG, "the count of parameters should be more than three!\n");
return -1;
}
in_filename = argv[1];
aac_filename = argv[2];
if(in_filename == NULL || aac_filename == NULL)
{
av_log(NULL, AV_LOG_DEBUG, "src or dts file is null, plz check them!\n");
return -1;
}
aac_fd = fopen(aac_filename, "wb");
if (!aac_fd)
{
av_log(NULL, AV_LOG_DEBUG, "Could not open destination file %s\n", aac_filename);
return -1;
}
if((ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL)) < 0)
{
av_strerror(ret, errors, 1024);
av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n",
in_filename,
ret,
errors);
return -1;
}
if((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0)
{
av_strerror(ret, errors, 1024);
av_log(NULL, AV_LOG_DEBUG, "failed to find stream information: %s, %d(%s)\n",
in_filename,
ret,
errors);
return -1;
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
av_init_packet(&pkt);
audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if(audio_index < 0)
{
av_log(NULL, AV_LOG_DEBUG, "Could not find %s stream in input file %s\n",
av_get_media_type_string(AVMEDIA_TYPE_AUDIO),
in_filename);
return AVERROR(EINVAL);
}
printf("audio profile:%d, FF_PROFILE_AAC_LOW:%d\n",
ifmt_ctx->streams[audio_index]->codecpar->profile,
FF_PROFILE_AAC_LOW);
if(ifmt_ctx->streams[audio_index]->codecpar->codec_id != AV_CODEC_ID_AAC)
{
printf("the media file no contain AAC stream, it's codec_id is %d\n",
ifmt_ctx->streams[audio_index]->codecpar->codec_id);
goto failed;
}
while(av_read_frame(ifmt_ctx, &pkt) >=0 )
{
if(pkt.stream_index == audio_index)
{
char adts_header_buf[7] = {0};
adts_header(adts_header_buf, pkt.size,
ifmt_ctx->streams[audio_index]->codecpar->profile,
ifmt_ctx->streams[audio_index]->codecpar->sample_rate,
ifmt_ctx->streams[audio_index]->codecpar->channels);
fwrite(adts_header_buf, 1, 7, aac_fd);
len = fwrite( pkt.data, 1, pkt.size, aac_fd);
if(len != pkt.size)
{
av_log(NULL, AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)\n",
len,
pkt.size);
}
}
av_packet_unref(&pkt);
}
failed:
if(ifmt_ctx)
{
avformat_close_input(&ifmt_ctx);
}
if(aac_fd)
{
fclose(aac_fd);
}
return 0;
}
三、从媒体文件中提取出h264视频帧到本地
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>
static char err_buf[128] = {0};
static char* av_get_err(int errnum)
{
av_strerror(errnum, err_buf, 128);
return err_buf;
}
int main(int argc, char **argv)
{
AVFormatContext *ifmt_ctx = NULL;
int videoindex = -1;
AVPacket *pkt = NULL;
int ret = -1;
int file_end = 0;
if(argc < 3)
{
printf("usage inputfile outfile\n");
return -1;
}
FILE *outfp=fopen(argv[2],"wb");
printf("in:%s out:%s\n", argv[1], argv[2]);
ifmt_ctx = avformat_alloc_context();
if (!ifmt_ctx)
{
printf("[error] Could not allocate context.\n");
return -1;
}
ret = avformat_open_input(&ifmt_ctx,argv[1], NULL, NULL);
if(ret != 0)
{
printf("[error]avformat_open_input: %s\n", av_get_err(ret));
return -1;
}
ret = avformat_find_stream_info(ifmt_ctx, NULL);
if(ret < 0)
{
printf("[error]avformat_find_stream_info: %s\n", av_get_err(ret));
avformat_close_input(&ifmt_ctx);
return -1;
}
videoindex = -1;
videoindex = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if(videoindex == -1)
{
printf("Didn't find a video stream.\n");
avformat_close_input(&ifmt_ctx);
return -1;
}
pkt = av_packet_alloc();
av_init_packet(pkt);
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[videoindex]->codecpar);
av_bsf_init(bsf_ctx);
file_end = 0;
while (0 == file_end)
{
if((ret = av_read_frame(ifmt_ctx, pkt)) < 0)
{
file_end = 1;
printf("read file end: ret:%d\n", ret);
}
if(ret == 0 && pkt->stream_index == videoindex)
{
#if 0
int input_size = pkt->size;
int out_pkt_count = 0;
if (av_bsf_send_packet(bsf_ctx, pkt) != 0)
{
av_packet_unref(pkt);
continue;
}
av_packet_unref(pkt);
while(av_bsf_receive_packet(bsf_ctx, pkt) == 0)
{
out_pkt_count++;
size_t size = fwrite(pkt->data, 1, pkt->size, outfp);
if(size != pkt->size)
{
printf("fwrite failed-> write:%u, pkt_size:%u\n", size, pkt->size);
}
av_packet_unref(pkt);
}
if(out_pkt_count >= 2)
{
printf("cur pkt(size:%d) only get 1 out pkt, it get %d pkts\n",
input_size, out_pkt_count);
}
#else
size_t size = fwrite(pkt->data, 1, pkt->size, outfp);
if(size != pkt->size)
{
printf("fwrite failed-> write:%u, pkt_size:%u\n", size, pkt->size);
}
av_packet_unref(pkt);
#endif
}
else
{
if(ret == 0)
av_packet_unref(pkt);
}
}
if(outfp)
fclose(outfp);
if(bsf_ctx)
av_bsf_free(&bsf_ctx);
if(pkt)
av_packet_free(&pkt);
if(ifmt_ctx)
avformat_close_input(&ifmt_ctx);
printf("finish\n");
return 0;
}
四、flv解封装
(1)FlvMetaData.cpp
#include "FlvMetaData.h"
FlvMetaData::FlvMetaData(uint8_t *meta, unsigned int length) {
m_meta = meta;
m_length = length;
m_duration = 0;
m_width = 0;
m_height = 0;
m_framerate = 0;
m_videodatarate = 0;
m_audiodatarate = 0;
m_videocodecid = 0;
m_audiosamplerate = 0;
m_audiosamplesize = 0;
m_stereo = false;
parseMeta();
}
FlvMetaData::FlvMetaData(const FlvMetaData& r) {
m_length = r.m_length;
m_meta = new uint8_t[m_length];
memcpy(m_meta, r.m_meta, m_length);
m_duration = r.m_duration;
m_width = r.m_width;
m_height = r.m_height;
m_framerate = r.m_framerate;
m_videodatarate = r.m_videodatarate;
m_audiodatarate = r.m_audiodatarate;
m_videocodecid = r.m_videocodecid;
m_audiosamplerate = r.m_audiosamplerate;
m_audiosamplesize = r.m_audiosamplesize;
m_stereo = r.m_stereo;
}
FlvMetaData& FlvMetaData::operator=(const FlvMetaData& r) {
if(this == &r) {
return *this;
}
if(m_meta != NULL) {
delete m_meta;
}
m_length = r.m_length;
m_meta = new uint8_t[m_length];
memcpy(m_meta, r.m_meta, m_length);
m_duration = r.m_duration;
m_width = r.m_width;
m_height = r.m_height;
m_framerate = r.m_framerate;
m_videodatarate = r.m_videodatarate;
m_audiodatarate = r.m_audiodatarate;
m_videocodecid = r.m_videocodecid;
m_audiosamplerate = r.m_audiosamplerate;
m_audiosamplesize = r.m_audiosamplesize;
m_stereo = r.m_stereo;
return *this;
}
FlvMetaData::~FlvMetaData() {
if(m_meta != NULL) {
delete m_meta;
m_meta = NULL;
}
}
void FlvMetaData::parseMeta() {
unsigned int arrayLen = 0;
unsigned int offset = TAG_HEAD_LEN + 13;
unsigned int nameLen = 0;
double numValue = 0;
bool boolValue = false;
if(m_meta[offset++] == 0x08) {
arrayLen |= m_meta[offset++];
arrayLen = arrayLen << 8;
arrayLen |= m_meta[offset++];
arrayLen = arrayLen << 8;
arrayLen |= m_meta[offset++];
arrayLen = arrayLen << 8;
arrayLen |= m_meta[offset++];
} else {
cerr << "metadata format error!!!" << endl;
return ;
}
for(unsigned int i = 0; i < arrayLen; i++) {
numValue = 0;
boolValue = false;
nameLen = 0;
nameLen |= m_meta[offset++];
nameLen = nameLen << 8;
nameLen |= m_meta[offset++];
char name[nameLen + 1];
#if DEBUG
printf("\norign \n");
for(unsigned int i = 0; i < nameLen + 3; i++) {
printf("%x ", m_meta[offset + i]);
}
printf("\n");
#endif
memset(name, 0, sizeof(name));
memcpy(name, &m_meta[offset], nameLen);
name[nameLen + 1] = '\0';
offset += nameLen;
#if DEBUG
printf("memcpy\n");
for(unsigned int i = 0; i < nameLen; i++) {
printf("%x ", name[i]);
}
printf("\n");
#endif
switch(m_meta[offset++]) {
case 0x0:
numValue = hexStr2double(&m_meta[offset], 8);
offset += 8;
break;
case 0x1:
if(offset++ != 0x00) {
boolValue = true;
}
break;
case 0x2:
nameLen = 0;
nameLen |= m_meta[offset++];
nameLen = nameLen << 8;
nameLen |= m_meta[offset++];
offset += nameLen;
break;
case 0x12:
nameLen = 0;
nameLen |= m_meta[offset++];
nameLen = nameLen << 8;
nameLen |= m_meta[offset++];
nameLen = nameLen << 8;
nameLen |= m_meta[offset++];
nameLen = nameLen << 8;
nameLen |= m_meta[offset++];
offset += nameLen;
break;
default:
break;
}
if(strncmp(name, "duration", 8) == 0) {
m_duration = numValue;
} else if(strncmp(name, "width", 5) == 0) {
m_width = numValue;
} else if(strncmp(name, "height", 6) == 0) {
m_height = numValue;
} else if(strncmp(name, "framerate", 9) == 0) {
m_framerate = numValue;
} else if(strncmp(name, "videodatarate", 13) == 0) {
m_videodatarate = numValue;
} else if(strncmp(name, "audiodatarate", 13) == 0) {
m_audiodatarate = numValue;
} else if(strncmp(name, "videocodecid", 12) == 0) {
m_videocodecid = numValue;
} else if(strncmp(name, "audiosamplerate", 15) == 0) {
m_audiosamplerate = numValue;
} else if(strncmp(name, "audiosamplesize", 15) == 0) {
m_audiosamplesize = numValue;
} else if(strncmp(name, "audiocodecid", 12) == 0) {
m_audiocodecid = numValue;
} else if(strncmp(name, "stereo", 6) == 0) {
m_stereo = boolValue;
}
}
}
double FlvMetaData::hexStr2double(const uint8_t* hex, const unsigned int length) {
double ret = 0;
char hexstr[length * 2];
memset(hexstr, 0, sizeof(hexstr));
for(unsigned int i = 0; i < length; i++) {
sprintf(hexstr + i * 2, "%02x", hex[i]);
}
sscanf(hexstr, "%llx", (unsigned long long*)&ret);
return ret;
}
double FlvMetaData::getDuration() {
return m_duration;
}
double FlvMetaData::getWidth() {
return m_width;
}
double FlvMetaData::getHeight() {
return m_height;
}
double FlvMetaData::getFramerate() {
return m_framerate;
}
double FlvMetaData::getVideoDatarate() {
return m_videodatarate;
}
double FlvMetaData::getAudioDatarate() {
return m_audiodatarate;
}
double FlvMetaData::getVideoCodecId() {
return m_videocodecid;
}
double FlvMetaData::getAudioSamplerate() {
return m_audiosamplerate;
}
double FlvMetaData::getAudioSamplesize() {
return m_audiosamplesize;
}
double FlvMetaData::getAudioCodecId() {
return m_audiocodecid;
}
bool FlvMetaData::getStereo() {
return m_stereo;
}
(2) FlvMetaData.h
#ifndef FLVMETADATA_H
#define FLVMETADATA_H
#include <cstdint>
class FlvMetaData
{
public:
FlvMetaData(uint8_t *meta, uint32_t length);
~FlvMetaData();
FlvMetaData(const FlvMetaData&);
FlvMetaData& operator=(const FlvMetaData&);
double getDuration();
double getWidth();
double getHeight();
double getFramerate();
double getVideoDatarate();
double getAudioDatarate();
double getVideoCodecId();
double getAudioCodecId();
double getAudioSamplerate();
double getAudioSamplesize();
bool getStereo();
private:
double hexStr2double(const uint8_t* hex, const uint32_t length);
void parseMeta();
private:
uint8_t *m_meta;
uint32_t m_length;
double m_duration;
double m_width;
double m_height;
double m_framerate;
double m_videodatarate;
double m_audiodatarate;
double m_videocodecid;
double m_audiocodecid;
double m_audiosamplerate;
double m_audiosamplesize;
bool m_stereo;
};
#endif
(3)FlvPrase.cpp
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <iostream>
#include <fstream>
#include "FlvParser.h"
using namespace std;
#define CheckBuffer(x) { if ((nBufSize-nOffset)<(x)) { nUsedLen = nOffset; return 0;} }
int CFlvParser::CAudioTag::_aacProfile;
int CFlvParser::CAudioTag::_sampleRateIndex;
int CFlvParser::CAudioTag::_channelConfig;
static const uint32_t nH264StartCode = 0x01000000;
CFlvParser::CFlvParser()
{
_pFlvHeader = NULL;
_vjj = new CVideojj();
}
CFlvParser::~CFlvParser()
{
for (int i = 0; i < _vpTag.size(); i++)
{
DestroyTag(_vpTag[i]);
delete _vpTag[i];
}
if (_vjj != NULL)
delete _vjj;
}
int CFlvParser::Parse(uint8_t *pBuf, int nBufSize, int &nUsedLen)
{
int nOffset = 0;
if (_pFlvHeader == 0)
{
CheckBuffer(9);
_pFlvHeader = CreateFlvHeader(pBuf+nOffset);
nOffset += _pFlvHeader->nHeadSize;
}
while (1)
{
CheckBuffer(15);
int nPrevSize = ShowU32(pBuf + nOffset);
nOffset += 4;
Tag *pTag = CreateTag(pBuf + nOffset, nBufSize-nOffset);
if (pTag == NULL)
{
nOffset -= 4;
break;
}
nOffset += (11 + pTag->_header.nDataSize);
_vpTag.push_back(pTag);
}
nUsedLen = nOffset;
return 0;
}
int CFlvParser::PrintInfo()
{
Stat();
cout << "vnum: " << _sStat.nVideoNum << " , anum: " << _sStat.nAudioNum << " , mnum: " << _sStat.nMetaNum << endl;
cout << "maxTimeStamp: " << _sStat.nMaxTimeStamp << " ,nLengthSize: " << _sStat.nLengthSize << endl;
cout << "Vjj SEI num: " << _vjj->_vVjjSEI.size() << endl;
for (int i = 0; i < _vjj->_vVjjSEI.size(); i++)
cout << "SEI time : " << _vjj->_vVjjSEI[i].nTimeStamp << endl;
return 1;
}
int CFlvParser::DumpH264(const std::string &path)
{
fstream f;
f.open(path.c_str(), ios_base::out|ios_base::binary);
vector<Tag *>::iterator it_tag;
for (it_tag = _vpTag.begin(); it_tag != _vpTag.end(); it_tag++)
{
if ((*it_tag)->_header.nType != 0x09)
continue;
f.write((char *)(*it_tag)->_pMedia, (*it_tag)->_nMediaLen);
}
f.close();
return 1;
}
int CFlvParser::DumpAAC(const std::string &path)
{
fstream f;
f.open(path.c_str(), ios_base::out | ios_base::binary);
vector<Tag *>::iterator it_tag;
for (it_tag = _vpTag.begin(); it_tag != _vpTag.end(); it_tag++)
{
if ((*it_tag)->_header.nType != 0x08)
continue;
CAudioTag *pAudioTag = (CAudioTag *)(*it_tag);
if (pAudioTag->_nSoundFormat != 10)
continue;
if (pAudioTag->_nMediaLen!=0)
f.write((char *)(*it_tag)->_pMedia, (*it_tag)->_nMediaLen);
}
f.close();
return 1;
}
int CFlvParser::DumpFlv(const std::string &path)
{
fstream f;
f.open(path.c_str(), ios_base::out | ios_base::binary);
f.write((char *)_pFlvHeader->pFlvHeader, _pFlvHeader->nHeadSize);
uint32_t nLastTagSize = 0;
vector<Tag *>::iterator it_tag;
for (it_tag = _vpTag.begin(); it_tag < _vpTag.end(); it_tag++)
{
uint32_t nn = WriteU32(nLastTagSize);
f.write((char *)&nn, 4);
if ((*it_tag)->_header.nType == 0x09 && *((*it_tag)->_pTagData + 1) == 0x01) {
bool duplicate = false;
uint8_t *pStartCode = (*it_tag)->_pTagData + 5 + _nNalUnitLength;
unsigned nalu_len = 0;
uint8_t *p_nalu_len=(uint8_t *)&nalu_len;
switch (_nNalUnitLength) {
case 4:
nalu_len = ShowU32((*it_tag)->_pTagData + 5);
break;
case 3:
nalu_len = ShowU24((*it_tag)->_pTagData + 5);
break;
case 2:
nalu_len = ShowU16((*it_tag)->_pTagData + 5);
break;
default:
nalu_len = ShowU8((*it_tag)->_pTagData + 5);
break;
}
uint8_t *pStartCodeRecord = pStartCode;
int i;
for (i = 0; i < (*it_tag)->_header.nDataSize - 5 - _nNalUnitLength - 4; ++i) {
if (pStartCode[i] == 0x00 && pStartCode[i+1] == 0x00 && pStartCode[i+2] == 0x00 &&
pStartCode[i+3] == 0x01) {
if (pStartCode[i+4] == 0x67) {
i += 4;
continue;
}
else if (pStartCode[i+4] == 0x68) {
i += 4;
continue;
}
else if (pStartCode[i+4] == 0x06) {
i += 4;
continue;
}
else {
i += 4;
duplicate = true;
break;
}
}
}
if (duplicate) {
nalu_len -= i;
(*it_tag)->_header.nDataSize -= i;
uint8_t *p = (uint8_t *)&((*it_tag)->_header.nDataSize);
(*it_tag)->_pTagHeader[1] = p[2];
(*it_tag)->_pTagHeader[2] = p[1];
(*it_tag)->_pTagHeader[3] = p[0];
f.write((char *)(*it_tag)->_pTagHeader, 11);
switch (_nNalUnitLength) {
case 4:
*((*it_tag)->_pTagData + 5) = p_nalu_len[3];
*((*it_tag)->_pTagData + 6) = p_nalu_len[2];
*((*it_tag)->_pTagData + 7) = p_nalu_len[1];
*((*it_tag)->_pTagData + 8) = p_nalu_len[0];
break;
case 3:
*((*it_tag)->_pTagData + 5) = p_nalu_len[2];
*((*it_tag)->_pTagData + 6) = p_nalu_len[1];
*((*it_tag)->_pTagData + 7) = p_nalu_len[0];
break;
case 2:
*((*it_tag)->_pTagData + 5) = p_nalu_len[1];
*((*it_tag)->_pTagData + 6) = p_nalu_len[0];
break;
default:
*((*it_tag)->_pTagData + 5) = p_nalu_len[0];
break;
}
f.write((char *)(*it_tag)->_pTagData, pStartCode - (*it_tag)->_pTagData);
f.write((char *)pStartCode + i, (*it_tag)->_header.nDataSize - (pStartCode - (*it_tag)->_pTagData));
} else {
f.write((char *)(*it_tag)->_pTagHeader, 11);
f.write((char *)(*it_tag)->_pTagData, (*it_tag)->_header.nDataSize);
}
} else {
f.write((char *)(*it_tag)->_pTagHeader, 11);
f.write((char *)(*it_tag)->_pTagData, (*it_tag)->_header.nDataSize);
}
nLastTagSize = 11 + (*it_tag)->_header.nDataSize;
}
uint32_t nn = WriteU32(nLastTagSize);
f.write((char *)&nn, 4);
f.close();
return 1;
}
int CFlvParser::Stat()
{
for (int i = 0; i < _vpTag.size(); i++)
{
switch (_vpTag[i]->_header.nType)
{
case 0x08:
_sStat.nAudioNum++;
break;
case 0x09:
StatVideo(_vpTag[i]);
break;
case 0x12:
_sStat.nMetaNum++;
break;
default:
;
}
}
return 1;
}
int CFlvParser::StatVideo(Tag *pTag)
{
_sStat.nVideoNum++;
_sStat.nMaxTimeStamp = pTag->_header.nTimeStamp;
if (pTag->_pTagData[0] == 0x17 && pTag->_pTagData[1] == 0x00)
{
_sStat.nLengthSize = (pTag->_pTagData[9] & 0x03) + 1;
}
return 1;
}
CFlvParser::FlvHeader *CFlvParser::CreateFlvHeader(uint8_t *pBuf)
{
FlvHeader *pHeader = new FlvHeader;
pHeader->nVersion = pBuf[3];
pHeader->bHaveAudio = (pBuf[4] >> 2) & 0x01;
pHeader->bHaveVideo = (pBuf[4] >> 0) & 0x01;
pHeader->nHeadSize = ShowU32(pBuf + 5);
pHeader->pFlvHeader = new uint8_t[pHeader->nHeadSize];
memcpy(pHeader->pFlvHeader, pBuf, pHeader->nHeadSize);
return pHeader;
}
int CFlvParser::DestroyFlvHeader(FlvHeader *pHeader)
{
if (pHeader == NULL)
return 0;
delete pHeader->pFlvHeader;
return 1;
}
void CFlvParser::Tag::Init(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen)
{
memcpy(&_header, pHeader, sizeof(TagHeader));
_pTagHeader = new uint8_t[11];
memcpy(_pTagHeader, pBuf, 11);
_pTagData = new uint8_t[_header.nDataSize];
memcpy(_pTagData, pBuf + 11, _header.nDataSize);
}
CFlvParser::CVideoTag::CVideoTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen, CFlvParser *pParser)
{
Init(pHeader, pBuf, nLeftLen);
uint8_t *pd = _pTagData;
_nFrameType = (pd[0] & 0xf0) >> 4;
_nCodecID = pd[0] & 0x0f;
if (_header.nType == 0x09 && _nCodecID == 7)
{
ParseH264Tag(pParser);
}
}
CFlvParser::CAudioTag::CAudioTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen, CFlvParser *pParser)
{
Init(pHeader, pBuf, nLeftLen);
uint8_t *pd = _pTagData;
_nSoundFormat = (pd[0] & 0xf0) >> 4;
_nSoundRate = (pd[0] & 0x0c) >> 2;
_nSoundSize = (pd[0] & 0x02) >> 1;
_nSoundType = (pd[0] & 0x01);
if (_nSoundFormat == 10)
{
ParseAACTag(pParser);
}
}
int CFlvParser::CAudioTag::ParseAACTag(CFlvParser *pParser)
{
uint8_t *pd = _pTagData;
int nAACPacketType = pd[1];
if (nAACPacketType == 0)
{
ParseAudioSpecificConfig(pParser, pd);
}
else if (nAACPacketType == 1)
{
ParseRawAAC(pParser, pd);
}
else
{
}
return 1;
}
int CFlvParser::CAudioTag::ParseAudioSpecificConfig(CFlvParser *pParser, uint8_t *pTagData)
{
uint8_t *pd = _pTagData;
_aacProfile = ((pd[2]&0xf8)>>3);
_sampleRateIndex = ((pd[2]&0x07)<<1) | (pd[3]>>7);
_channelConfig = (pd[3]>>3) & 0x0f;
printf("----- AAC ------\n");
printf("profile:%d\n", _aacProfile);
printf("sample rate index:%d\n", _sampleRateIndex);
printf("channel config:%d\n", _channelConfig);
_pMedia = NULL;
_nMediaLen = 0;
return 1;
}
int CFlvParser::CAudioTag::ParseRawAAC(CFlvParser *pParser, uint8_t *pTagData)
{
uint64_t bits = 0;
int dataSize = _header.nDataSize - 2;
WriteU64(bits, 12, 0xFFF);
WriteU64(bits, 1, 0);
WriteU64(bits, 2, 0);
WriteU64(bits, 1, 1);
WriteU64(bits, 2, _aacProfile - 1);
WriteU64(bits, 4, _sampleRateIndex);
WriteU64(bits, 1, 0);
WriteU64(bits, 3, _channelConfig);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 13, 7 + dataSize);
WriteU64(bits, 11, 0x7FF);
WriteU64(bits, 2, 0);
_nMediaLen = 7 + dataSize;
_pMedia = new uint8_t[_nMediaLen];
uint8_t p64[8];
p64[0] = (uint8_t)(bits >> 56);
p64[1] = (uint8_t)(bits >> 48);
p64[2] = (uint8_t)(bits >> 40);
p64[3] = (uint8_t)(bits >> 32);
p64[4] = (uint8_t)(bits >> 24);
p64[5] = (uint8_t)(bits >> 16);
p64[6] = (uint8_t)(bits >> 8);
p64[7] = (uint8_t)(bits);
memcpy(_pMedia, p64+1, 7);
memcpy(_pMedia + 7, pTagData + 2, dataSize);
return 1;
}
CFlvParser::CMetaDataTag::CMetaDataTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen, CFlvParser *pParser)
{
Init(pHeader, pBuf, nLeftLen);
uint8_t *pd = _pTagData;
m_amf1_type = ShowU8(pd+0);
m_amf1_size = ShowU16(pd+1);
if(m_amf1_type != 2)
{
printf("no metadata\n");
return;
}
if(strncmp((const char *)"onMetaData", (const char *)(pd + 3), 10) == 0)
parseMeta(pParser);
}
double CFlvParser::CMetaDataTag::hexStr2double(const uint8_t* hex,
const uint32_t length) {
double ret = 0;
char hexstr[length * 2];
memset(hexstr, 0, sizeof(hexstr));
for(uint32_t i = 0; i < length; i++)
{
sprintf(hexstr + i * 2, "%02x", hex[i]);
}
sscanf(hexstr, "%llx", (unsigned long long*)&ret);
return ret;
}
int CFlvParser::CMetaDataTag::parseMeta(CFlvParser *pParser)
{
uint8_t *pd = _pTagData;
int dataSize = _header.nDataSize;
uint32_t arrayLen = 0;
uint32_t offset = 13;
uint32_t nameLen = 0;
double doubleValue = 0;
string strValue = "";
bool boolValue = false;
uint32_t valueLen = 0;
uint8_t u8Value = 0;
if(pd[offset++] == 0x08)
{
arrayLen = ShowU32(pd + offset);
offset += 4;
printf("ArrayLen = %d\n", arrayLen);
}
else
{
printf("metadata format error!!!");
return -1;
}
for(uint32_t i = 0; i < arrayLen; i++)
{
doubleValue = 0;
boolValue = false;
strValue = "";
nameLen = ShowU16(pd + offset);
offset += 2;
char name[nameLen + 1];
memset(name, 0, sizeof(name));
memcpy(name, &pd[offset], nameLen);
name[nameLen + 1] = '\0';
offset += nameLen;
uint8_t amfType = pd[offset++];
switch(amfType)
{
case 0x0:
doubleValue = hexStr2double(&pd[offset], 8);
offset += 8;
break;
case 0x1:
u8Value = ShowU8(pd+offset);
offset += 1;
if(u8Value != 0x00)
boolValue = true;
else
boolValue = false;
break;
case 0x2:
valueLen = ShowU16(pd + offset);
offset += 2;
strValue.append(pd + offset, pd + offset + valueLen);
strValue.append("");
offset += valueLen;
break;
default:
printf("un handle amfType:%d\n", amfType);
break;
}
if(strncmp(name, "duration", 8) == 0)
{
m_duration = doubleValue;
}
else if(strncmp(name, "width", 5) == 0)
{
m_width = doubleValue;
}
else if(strncmp(name, "height", 6) == 0)
{
m_height = doubleValue;
}
else if(strncmp(name, "videodatarate", 13) == 0)
{
m_videodatarate = doubleValue;
}
else if(strncmp(name, "framerate", 9) == 0)
{
m_framerate = doubleValue;
}
else if(strncmp(name, "videocodecid", 12) == 0)
{
m_videocodecid = doubleValue;
}
else if(strncmp(name, "audiodatarate", 13) == 0)
{
m_audiodatarate = doubleValue;
}
else if(strncmp(name, "audiosamplerate", 15) == 0)
{
m_audiosamplerate = doubleValue;
}
else if(strncmp(name, "audiosamplesize", 15) == 0)
{
m_audiosamplesize = doubleValue;
}
else if(strncmp(name, "stereo", 6) == 0)
{
m_stereo = boolValue;
}
else if(strncmp(name, "audiocodecid", 12) == 0)
{
m_audiocodecid = doubleValue;
}
else if(strncmp(name, "major_brand", 11) == 0)
{
m_major_brand = strValue;
}
else if(strncmp(name, "minor_version", 13) == 0)
{
m_minor_version = strValue;
}
else if(strncmp(name, "compatible_brands", 17) == 0)
{
m_compatible_brands = strValue;
}
else if(strncmp(name, "encoder", 7) == 0)
{
m_encoder = strValue;
}
else if(strncmp(name, "filesize", 8) == 0)
{
m_filesize = doubleValue;
}
}
printMeta();
return 1;
}
void CFlvParser::CMetaDataTag::printMeta()
{
printf("\nduration: %0.2lfs, filesize: %.0lfbytes\n", m_duration, m_filesize);
printf("width: %0.0lf, height: %0.0lf\n", m_width, m_height);
printf("videodatarate: %0.2lfkbps, framerate: %0.0lffps\n", m_videodatarate, m_framerate);
printf("videocodecid: %0.0lf\n", m_videocodecid);
printf("audiodatarate: %0.2lfkbps, audiosamplerate: %0.0lfKhz\n",
m_audiodatarate, m_audiosamplerate);
printf("audiosamplesize: %0.0lfbit, stereo: %d\n", m_audiosamplesize, m_stereo);
printf("audiocodecid: %0.0lf\n", m_audiocodecid);
printf("major_brand: %s, minor_version: %s\n", m_major_brand.c_str(), m_minor_version.c_str());
printf("compatible_brands: %s, encoder: %s\n\n", m_compatible_brands.c_str(), m_encoder.c_str());
}
CFlvParser::Tag *CFlvParser::CreateTag(uint8_t *pBuf, int nLeftLen)
{
TagHeader header;
header.nType = ShowU8(pBuf+0);
header.nDataSize = ShowU24(pBuf + 1);
header.nTimeStamp = ShowU24(pBuf + 4);
header.nTSEx = ShowU8(pBuf + 7);
header.nStreamID = ShowU24(pBuf + 8);
header.nTotalTS = (uint32_t)((header.nTSEx << 24)) + header.nTimeStamp;
if ((header.nDataSize + 11) > nLeftLen)
{
return NULL;
}
Tag *pTag;
switch (header.nType) {
case 0x09:
pTag = new CVideoTag(&header, pBuf, nLeftLen, this);
break;
case 0x08:
pTag = new CAudioTag(&header, pBuf, nLeftLen, this);
break;
case 0x12:
pTag = new CMetaDataTag(&header, pBuf, nLeftLen, this);
break;
default:
pTag = new Tag();
pTag->Init(&header, pBuf, nLeftLen);
}
return pTag;
}
int CFlvParser::DestroyTag(Tag *pTag)
{
if (pTag->_pMedia != NULL)
delete []pTag->_pMedia;
if (pTag->_pTagData!=NULL)
delete []pTag->_pTagData;
if (pTag->_pTagHeader != NULL)
delete []pTag->_pTagHeader;
return 1;
}
int CFlvParser::CVideoTag::ParseH264Tag(CFlvParser *pParser)
{
uint8_t *pd = _pTagData;
int nAVCPacketType = pd[1];
int nCompositionTime = CFlvParser::ShowU24(pd + 2);
if (nAVCPacketType == 0)
{
ParseH264Configuration(pParser, pd);
}
else if (nAVCPacketType == 1)
{
ParseNalu(pParser, pd);
}
else
{
}
return 1;
}
int CFlvParser::CVideoTag::ParseH264Configuration(CFlvParser *pParser, uint8_t *pTagData)
{
uint8_t *pd = pTagData;
pParser->_nNalUnitLength = (pd[9] & 0x03) + 1;
int sps_size, pps_size;
sps_size = CFlvParser::ShowU16(pd + 11);
pps_size = CFlvParser::ShowU16(pd + 11 + (2 + sps_size) + 1);
_nMediaLen = 4 + sps_size + 4 + pps_size;
_pMedia = new uint8_t[_nMediaLen];
memcpy(_pMedia, &nH264StartCode, 4);
memcpy(_pMedia + 4, pd + 11 + 2, sps_size);
memcpy(_pMedia + 4 + sps_size, &nH264StartCode, 4);
memcpy(_pMedia + 4 + sps_size + 4, pd + 11 + 2 + sps_size + 2 + 1, pps_size);
return 1;
}
int CFlvParser::CVideoTag::ParseNalu(CFlvParser *pParser, uint8_t *pTagData)
{
uint8_t *pd = pTagData;
int nOffset = 0;
_pMedia = new uint8_t[_header.nDataSize+10];
_nMediaLen = 0;
nOffset = 5;
while (1)
{
if (nOffset >= _header.nDataSize)
break;
int nNaluLen;
switch (pParser->_nNalUnitLength)
{
case 4:
nNaluLen = CFlvParser::ShowU32(pd + nOffset);
break;
case 3:
nNaluLen = CFlvParser::ShowU24(pd + nOffset);
break;
case 2:
nNaluLen = CFlvParser::ShowU16(pd + nOffset);
break;
default:
nNaluLen = CFlvParser::ShowU8(pd + nOffset);
}
memcpy(_pMedia + _nMediaLen, &nH264StartCode, 4);
memcpy(_pMedia + _nMediaLen + 4, pd + nOffset + pParser->_nNalUnitLength, nNaluLen);
_nMediaLen += (4 + nNaluLen);
nOffset += (pParser->_nNalUnitLength + nNaluLen);
}
return 1;
}
(4) FlvParse.h
#ifndef FLVPARSER_H
#define FLVPARSER_H
#include <iostream>
#include <vector>
#include <stdint.h>
#include "Videojj.h"
using namespace std;
typedef unsigned long long uint64_t;
class CFlvParser
{
public:
CFlvParser();
virtual ~CFlvParser();
int Parse(uint8_t *pBuf, int nBufSize, int &nUsedLen);
int PrintInfo();
int DumpH264(const std::string &path);
int DumpAAC(const std::string &path);
int DumpFlv(const std::string &path);
private:
typedef struct FlvHeader_s
{
int nVersion;
int bHaveVideo;
int bHaveAudio;
int nHeadSize;
uint8_t *pFlvHeader;
} FlvHeader;
struct TagHeader
{
int nType;
int nDataSize;
int nTimeStamp;
int nTSEx;
int nStreamID;
uint32_t nTotalTS;
TagHeader() : nType(0), nDataSize(0), nTimeStamp(0), nTSEx(0), nStreamID(0), nTotalTS(0) {}
~TagHeader() {}
};
class Tag
{
public:
Tag() : _pTagHeader(NULL), _pTagData(NULL), _pMedia(NULL), _nMediaLen(0) {}
void Init(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen);
TagHeader _header;
uint8_t *_pTagHeader;
uint8_t *_pTagData;
uint8_t *_pMedia;
int _nMediaLen;
};
class CVideoTag : public Tag
{
public:
CVideoTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen, CFlvParser *pParser);
int _nFrameType;
int _nCodecID;
int ParseH264Tag(CFlvParser *pParser);
int ParseH264Configuration(CFlvParser *pParser, uint8_t *pTagData);
int ParseNalu(CFlvParser *pParser, uint8_t *pTagData);
};
class CAudioTag : public Tag
{
public:
CAudioTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen, CFlvParser *pParser);
int _nSoundFormat;
int _nSoundRate;
int _nSoundSize;
int _nSoundType;
static int _aacProfile;
static int _sampleRateIndex;
static int _channelConfig;
int ParseAACTag(CFlvParser *pParser);
int ParseAudioSpecificConfig(CFlvParser *pParser, uint8_t *pTagData);
int ParseRawAAC(CFlvParser *pParser, uint8_t *pTagData);
};
class CMetaDataTag : public Tag
{
public:
CMetaDataTag(TagHeader *pHeader, uint8_t *pBuf, int nLeftLen, CFlvParser *pParser);
double hexStr2double(const unsigned char* hex, const unsigned int length);
int parseMeta(CFlvParser *pParser);
void printMeta();
uint8_t m_amf1_type;
uint32_t m_amf1_size;
uint8_t m_amf2_type;
unsigned char *m_meta;
unsigned int m_length;
double m_duration;
double m_width;
double m_height;
double m_videodatarate;
double m_framerate;
double m_videocodecid;
double m_audiodatarate;
double m_audiosamplerate;
double m_audiosamplesize;
bool m_stereo;
double m_audiocodecid;
string m_major_brand;
string m_minor_version;
string m_compatible_brands;
string m_encoder;
double m_filesize;
};
struct FlvStat
{
int nMetaNum, nVideoNum, nAudioNum;
int nMaxTimeStamp;
int nLengthSize;
FlvStat() : nMetaNum(0), nVideoNum(0), nAudioNum(0), nMaxTimeStamp(0), nLengthSize(0){}
~FlvStat() {}
};
static uint32_t ShowU32(uint8_t *pBuf) { return (pBuf[0] << 24) | (pBuf[1] << 16) | (pBuf[2] << 8) | pBuf[3]; }
static uint32_t ShowU24(uint8_t *pBuf) { return (pBuf[0] << 16) | (pBuf[1] << 8) | (pBuf[2]); }
static uint32_t ShowU16(uint8_t *pBuf) { return (pBuf[0] << 8) | (pBuf[1]); }
static uint32_t ShowU8(uint8_t *pBuf) { return (pBuf[0]); }
static void WriteU64(uint64_t & x, int length, int value)
{
uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - length);
x = (x << length) | ((uint64_t)value & mask);
}
static uint32_t WriteU32(uint32_t n)
{
uint32_t nn = 0;
uint8_t *p = (uint8_t *)&n;
uint8_t *pp = (uint8_t *)&nn;
pp[0] = p[3];
pp[1] = p[2];
pp[2] = p[1];
pp[3] = p[0];
return nn;
}
friend class Tag;
private:
FlvHeader *CreateFlvHeader(uint8_t *pBuf);
int DestroyFlvHeader(FlvHeader *pHeader);
Tag *CreateTag(uint8_t *pBuf, int nLeftLen);
int DestroyTag(Tag *pTag);
int Stat();
int StatVideo(Tag *pTag);
int IsUserDataTag(Tag *pTag);
private:
FlvHeader* _pFlvHeader;
vector<Tag *> _vpTag;
FlvStat _sStat;
CVideojj *_vjj;
int _nNalUnitLength;
};
#endif
(5)main()
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include "FlvParser.h"
using namespace std;
void Process(fstream &fin, const char *filename);
int main(int argc, char *argv[])
{
cout << "Hi, this is FLV parser test program!\n";
if (argc != 3)
{
cout << "FlvParser.exe [input flv] [output flv]" << endl;
return 0;
}
fstream fin;
fin.open(argv[1], ios_base::in | ios_base::binary);
if (!fin)
return 0;
Process(fin, argv[2]);
fin.close();
return 1;
}
void Process(fstream &fin, const char *filename)
{
CFlvParser parser;
int nBufSize = 2*1024 * 1024;
int nFlvPos = 0;
uint8_t *pBuf, *pBak;
pBuf = new uint8_t[nBufSize];
pBak = new uint8_t[nBufSize];
while (1)
{
int nReadNum = 0;
int nUsedLen = 0;
fin.read((char *)pBuf + nFlvPos, nBufSize - nFlvPos);
nReadNum = fin.gcount();
if (nReadNum == 0)
break;
nFlvPos += nReadNum;
parser.Parse(pBuf, nFlvPos, nUsedLen);
if (nFlvPos != nUsedLen)
{
memcpy(pBak, pBuf + nUsedLen, nFlvPos - nUsedLen);
memcpy(pBuf, pBak, nFlvPos - nUsedLen);
}
nFlvPos -= nUsedLen;
}
parser.PrintInfo();
parser.DumpH264("parser.264");
parser.DumpAAC("parser.aac");
parser.DumpFlv(filename);
delete []pBak;
delete []pBuf;
}
(6) vadbg.cpp
#include <fstream>
#include "vadbg.h"
using namespace std;
namespace vadbg
{
void DumpString(std::string path, std::string str)
{
ofstream fin;
fin.open(path.c_str(), ios_base::out);
fin << str.c_str();
fin.close();
}
void DumpBuffer(std::string path, uint8_t *pBuffer, int nBufSize)
{
ofstream fin;
fin.open(path.c_str(), ios_base::out | ios_base::binary);
fin.write((char *)pBuffer, nBufSize);
fin.close();
}
}
(7)vadbg.h
#ifndef VADBG_H
#define VADBG_H
#include <iostream>
namespace vadbg
{
void DumpString(std::string path, std::string str);
void DumpBuffer(std::string path, uint8_t *pBuffer, int nBufSize);
}
#endif
(8)Videojj.cpp
#include <stdlib.h>
#include <string.h>
#include "vadbg.h"
#include "Videojj.h"
CVideojj::CVideojj()
{
}
CVideojj::~CVideojj()
{
int i;
for (i = 0; i < _vVjjSEI.size(); i++)
{
delete _vVjjSEI[i].szUD;
}
}
int CVideojj::Process(uint8_t *pNalu, int nNaluLen, int nTimeStamp)
{
if (pNalu[4] != 0x06 || pNalu[5] != 0x05)
return 0;
uint8_t *p = pNalu + 4 + 2;
while (*p++ == 0xff);
const char *szVideojjUUID = "VideojjLeonUUID";
char *pp = (char *)p;
for (int i = 0; i < strlen(szVideojjUUID); i++)
{
if (pp[i] != szVideojjUUID[i])
return 0;
}
VjjSEI sei;
sei.nTimeStamp = nTimeStamp;
sei.nLen = nNaluLen - (pp - (char *)pNalu) - 16 - 1;
sei.szUD = new char[sei.nLen];
memcpy(sei.szUD, pp + 16, sei.nLen);
_vVjjSEI.push_back(sei);
return 1;
}
(9)Videojj.h
#ifndef VIDEOJJ_H
#define VIDEOJJ_H
#include <vector>
#include <cstdint>
class CFlvParser;
typedef struct VjjSEI_s
{
char *szUD;
int nLen;
int nTimeStamp;
} VjjSEI;
class CVideojj
{
public:
CVideojj();
virtual ~CVideojj();
int Process(uint8_t *pNalu, int nNaluLen, int nTimeStamp);
private:
friend class CFlvParser;
std::vector<VjjSEI> _vVjjSEI;
};
#endif
五、音频解码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavutil/frame.h>
#include <libavutil/mem.h>
#include <libavcodec/avcodec.h>
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
static char err_buf[128] = {0};
static char* av_get_err(int errnum)
{
av_strerror(errnum, err_buf, 128);
return err_buf;
}
static void print_sample_format(const AVFrame *frame)
{
printf("ar-samplerate: %uHz\n", frame->sample_rate);
printf("ac-channel: %u\n", frame->channels);
printf("f-format: %u\n", frame->format);
}
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame,
FILE *outfile)
{
int i, ch;
int ret, data_size;
ret = avcodec_send_packet(dec_ctx, pkt);
if(ret == AVERROR(EAGAIN))
{
fprintf(stderr, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
}
else if (ret < 0)
{
fprintf(stderr, "Error submitting the packet to the decoder, err:%s, pkt_size:%d\n",
av_get_err(ret), pkt->size);
return;
}
while (ret >= 0)
{
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0)
{
fprintf(stderr, "Error during decoding\n");
exit(1);
}
data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
if (data_size < 0)
{
fprintf(stderr, "Failed to calculate data size\n");
exit(1);
}
static int s_print_format = 0;
if(s_print_format == 0)
{
s_print_format = 1;
print_sample_format(frame);
}
for (i = 0; i < frame->nb_samples; i++)
{
for (ch = 0; ch < dec_ctx->channels; ch++)
fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile);
}
}
}
int main(int argc, char **argv)
{
const char *outfilename;
const char *filename;
const AVCodec *codec;
AVCodecContext *codec_ctx= NULL;
AVCodecParserContext *parser = NULL;
int len = 0;
int ret = 0;
FILE *infile = NULL;
FILE *outfile = NULL;
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t *data = NULL;
size_t data_size = 0;
AVPacket *pkt = NULL;
AVFrame *decoded_frame = NULL;
if (argc <= 2)
{
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
exit(0);
}
filename = argv[1];
outfilename = argv[2];
pkt = av_packet_alloc();
enum AVCodecID audio_codec_id = AV_CODEC_ID_AAC;
if(strstr(filename, "aac") != NULL)
{
audio_codec_id = AV_CODEC_ID_AAC;
}
else if(strstr(filename, "mp3") != NULL)
{
audio_codec_id = AV_CODEC_ID_MP3;
}
else
{
printf("default codec id:%d\n", audio_codec_id);
}
codec = avcodec_find_decoder(audio_codec_id);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
parser = av_parser_init(codec->id);
if (!parser) {
fprintf(stderr, "Parser not found\n");
exit(1);
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
infile = fopen(filename, "rb");
if (!infile) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(codec_ctx);
exit(1);
}
data = inbuf;
data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, infile);
while (data_size > 0)
{
if (!decoded_frame)
{
if (!(decoded_frame = av_frame_alloc()))
{
fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
}
ret = av_parser_parse2(parser, codec_ctx, &pkt->data, &pkt->size,
data, data_size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0)
{
fprintf(stderr, "Error while parsing\n");
exit(1);
}
data += ret;
data_size -= ret;
if (pkt->size)
decode(codec_ctx, pkt, decoded_frame, outfile);
if (data_size < AUDIO_REFILL_THRESH)
{
memmove(inbuf, data, data_size);
data = inbuf;
len = fread(data + data_size, 1, AUDIO_INBUF_SIZE - data_size, infile);
if (len > 0)
data_size += len;
}
}
pkt->data = NULL;
pkt->size = 0;
decode(codec_ctx, pkt, decoded_frame, outfile);
fclose(outfile);
fclose(infile);
avcodec_free_context(&codec_ctx);
av_parser_close(parser);
av_frame_free(&decoded_frame);
av_packet_free(&pkt);
printf("main finish, please enter Enter and exit\n");
return 0;
}
六、视频解码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavutil/frame.h>
#include <libavutil/mem.h>
#include <libavcodec/avcodec.h>
#define VIDEO_INBUF_SIZE 20480
#define VIDEO_REFILL_THRESH 4096
static char err_buf[128] = {0};
static char* av_get_err(int errnum)
{
av_strerror(errnum, err_buf, 128);
return err_buf;
}
static void print_video_format(const AVFrame *frame)
{
printf("width: %u\n", frame->width);
printf("height: %u\n", frame->height);
printf("format: %u\n", frame->format);
}
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame,
FILE *outfile)
{
int ret;
ret = avcodec_send_packet(dec_ctx, pkt);
if(ret == AVERROR(EAGAIN))
{
fprintf(stderr, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
}
else if (ret < 0)
{
fprintf(stderr, "Error submitting the packet to the decoder, err:%s, pkt_size:%d\n",
av_get_err(ret), pkt->size);
return;
}
while (ret >= 0)
{
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0)
{
fprintf(stderr, "Error during decoding\n");
exit(1);
}
static int s_print_format = 0;
if(s_print_format == 0)
{
s_print_format = 1;
print_video_format(frame);
}
for(int j=0; j<frame->height; j++)
fwrite(frame->data[0] + j * frame->linesize[0], 1, frame->width, outfile);
for(int j=0; j<frame->height/2; j++)
fwrite(frame->data[1] + j * frame->linesize[1], 1, frame->width/2, outfile);
for(int j=0; j<frame->height/2; j++)
fwrite(frame->data[2] + j * frame->linesize[2], 1, frame->width/2, outfile);
}
}
int main(int argc, char **argv)
{
const char *outfilename;
const char *filename;
const AVCodec *codec;
AVCodecContext *codec_ctx= NULL;
AVCodecParserContext *parser = NULL;
int len = 0;
int ret = 0;
FILE *infile = NULL;
FILE *outfile = NULL;
uint8_t inbuf[VIDEO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t *data = NULL;
size_t data_size = 0;
AVPacket *pkt = NULL;
AVFrame *decoded_frame = NULL;
if (argc <= 2)
{
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
exit(0);
}
filename = argv[1];
outfilename = argv[2];
pkt = av_packet_alloc();
enum AVCodecID video_codec_id = AV_CODEC_ID_H264;
if(strstr(filename, "264") != NULL)
{
video_codec_id = AV_CODEC_ID_H264;
}
else if(strstr(filename, "mpeg2") != NULL)
{
video_codec_id = AV_CODEC_ID_MPEG2VIDEO;
}
else
{
printf("default codec id:%d\n", video_codec_id);
}
codec = avcodec_find_decoder(video_codec_id);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
parser = av_parser_init(codec->id);
if (!parser) {
fprintf(stderr, "Parser not found\n");
exit(1);
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
infile = fopen(filename, "rb");
if (!infile) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(codec_ctx);
exit(1);
}
data = inbuf;
data_size = fread(inbuf, 1, VIDEO_INBUF_SIZE, infile);
while (data_size > 0)
{
if (!decoded_frame)
{
if (!(decoded_frame = av_frame_alloc()))
{
fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
}
ret = av_parser_parse2(parser, codec_ctx, &pkt->data, &pkt->size,
data, data_size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0)
{
fprintf(stderr, "Error while parsing\n");
exit(1);
}
data += ret;
data_size -= ret;
if (pkt->size)
decode(codec_ctx, pkt, decoded_frame, outfile);
if (data_size < VIDEO_REFILL_THRESH)
{
memmove(inbuf, data, data_size);
data = inbuf;
len = fread(data + data_size, 1, VIDEO_INBUF_SIZE - data_size, infile);
if (len > 0)
data_size += len;
}
}
pkt->data = NULL;
pkt->size = 0;
decode(codec_ctx, pkt, decoded_frame, outfile);
fclose(outfile);
fclose(infile);
avcodec_free_context(&codec_ctx);
av_parser_close(parser);
av_frame_free(&decoded_frame);
av_packet_free(&pkt);
printf("main finish, please enter Enter and exit\n");
return 0;
}
七、Mp4解封装
#include <stdio.h>
#include "libavutil/log.h"
#include "libavformat/avformat.h"
#define ERROR_STRING_SIZE 1024
#define ADTS_HEADER_LEN 7;
const int sampling_frequencies[] = {
96000,
88200,
64000,
48000,
44100,
32000,
24000,
22050,
16000,
12000,
11025,
8000
};
int adts_header(char * const p_adts_header, const int data_length,
const int profile, const int samplerate,
const int channels)
{
int sampling_frequency_index = 3;
int adtsLen = data_length + 7;
int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);
int i = 0;
for(i = 0; i < frequencies_size; i++)
{
if(sampling_frequencies[i] == samplerate)
{
sampling_frequency_index = i;
break;
}
}
if(i >= frequencies_size)
{
printf("unsupport samplerate:%d\n", samplerate);
return -1;
}
p_adts_header[0] = 0xff;
p_adts_header[1] = 0xf0;
p_adts_header[1] |= (0 << 3);
p_adts_header[1] |= (0 << 1);
p_adts_header[1] |= 1;
p_adts_header[2] = (profile)<<6;
p_adts_header[2] |= (sampling_frequency_index & 0x0f)<<2;
p_adts_header[2] |= (0 << 1);
p_adts_header[2] |= (channels & 0x04)>>2;
p_adts_header[3] = (channels & 0x03)<<6;
p_adts_header[3] |= (0 << 5);
p_adts_header[3] |= (0 << 4);
p_adts_header[3] |= (0 << 3);
p_adts_header[3] |= (0 << 2);
p_adts_header[3] |= ((adtsLen & 0x1800) >> 11);
p_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);
p_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);
p_adts_header[5] |= 0x1f;
p_adts_header[6] = 0xfc;
return 0;
}
int main(int argc, char **argv)
{
if(argc != 4) {
printf("usage app input.mp4 out.h264 out.aac");
return -1;
}
char *in_filename = argv[1];
char *h264_filename = argv[2];
char *aac_filename = argv[3];
FILE *aac_fd = NULL;
FILE *h264_fd = NULL;
h264_fd = fopen(h264_filename, "wb");
if(!h264_fd) {
printf("fopen %s failed\n", h264_filename);
return -1;
}
aac_fd = fopen(aac_filename, "wb");
if(!aac_fd) {
printf("fopen %s failed\n", aac_filename);
return -1;
}
AVFormatContext *ifmt_ctx = NULL;
int video_index = -1;
int audio_index = -1;
AVPacket *pkt = NULL;
int ret = 0;
char errors[ERROR_STRING_SIZE+1];
ifmt_ctx = avformat_alloc_context();
if(!ifmt_ctx) {
printf("avformat_alloc_context failed\n");
return -1;
}
ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL);
if(ret < 0) {
av_strerror(ret, errors, ERROR_STRING_SIZE);
printf("avformat_open_input failed:%d\n", ret);
printf("avformat_open_input failed:%s\n", errors);
avformat_close_input(&ifmt_ctx);
return -1;
}
video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if(video_index == -1) {
printf("av_find_best_stream video_index failed\n");
avformat_close_input(&ifmt_ctx);
return -1;
}
audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if(audio_index == -1) {
printf("av_find_best_stream audio_index failed\n");
avformat_close_input(&ifmt_ctx);
return -1;
}
const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb");
if(!bsfilter) {
avformat_close_input(&ifmt_ctx);
printf("av_bsf_get_by_name h264_mp4toannexb failed\n");
return -1;
}
AVBSFContext *bsf_ctx = NULL;
ret = av_bsf_alloc(bsfilter, &bsf_ctx);
if(ret < 0) {
av_strerror(ret, errors, ERROR_STRING_SIZE);
printf("av_bsf_alloc failed:%s\n", errors);
avformat_close_input(&ifmt_ctx);
return -1;
}
ret = avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[video_index]->codecpar);
if(ret < 0) {
av_strerror(ret, errors, ERROR_STRING_SIZE);
printf("avcodec_parameters_copy failed:%s\n", errors);
avformat_close_input(&ifmt_ctx);
av_bsf_free(&bsf_ctx);
return -1;
}
ret = av_bsf_init(bsf_ctx);
if(ret < 0) {
av_strerror(ret, errors, ERROR_STRING_SIZE);
printf("av_bsf_init failed:%s\n", errors);
avformat_close_input(&ifmt_ctx);
av_bsf_free(&bsf_ctx);
return -1;
}
pkt = av_packet_alloc();
av_init_packet(pkt);
while (1) {
ret = av_read_frame(ifmt_ctx, pkt);
if(ret < 0 ) {
av_strerror(ret, errors, ERROR_STRING_SIZE);
printf("av_read_frame failed:%s\n", errors);
break;
}
if(pkt->stream_index == video_index) {
ret = av_bsf_send_packet(bsf_ctx, pkt);
if(ret < 0) {
av_strerror(ret, errors, ERROR_STRING_SIZE);
printf("av_bsf_send_packet failed:%s\n", errors);
av_packet_unref(pkt);
continue;
}
while (1) {
ret = av_bsf_receive_packet(bsf_ctx, pkt);
if(ret != 0) {
break;
}
size_t size = fwrite(pkt->data, 1, pkt->size, h264_fd);
if(size != pkt->size)
{
av_log(NULL, AV_LOG_DEBUG, "h264 warning, length of writed data isn't equal pkt->size(%d, %d)\n",
size,
pkt->size);
}
av_packet_unref(pkt);
}
} else if(pkt->stream_index == audio_index) {
char adts_header_buf[7] = {0};
adts_header(adts_header_buf, pkt->size,
ifmt_ctx->streams[audio_index]->codecpar->profile,
ifmt_ctx->streams[audio_index]->codecpar->sample_rate,
ifmt_ctx->streams[audio_index]->codecpar->channels);
fwrite(adts_header_buf, 1, 7, aac_fd);
size_t size = fwrite( pkt->data, 1, pkt->size, aac_fd);
if(size != pkt->size)
{
av_log(NULL, AV_LOG_DEBUG, "aac warning, length of writed data isn't equal pkt->size(%d, %d)\n",
size,
pkt->size);
}
av_packet_unref(pkt);
} else {
av_packet_unref(pkt);
}
}
printf("while finish\n");
failed:
if(h264_fd) {
fclose(h264_fd);
}
if(aac_fd) {
fclose(aac_fd);
}
if(pkt)
av_packet_free(&pkt);
if(ifmt_ctx)
avformat_close_input(&ifmt_ctx);
printf("Hello World!\n");
return 0;
}
八、AVIO
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavutil/frame.h>
#include <libavutil/mem.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#define BUF_SIZE 20480
static char* av_get_err(int errnum)
{
static char err_buf[128] = {0};
av_strerror(errnum, err_buf, 128);
return err_buf;
}
static void print_sample_format(const AVFrame *frame)
{
printf("ar-samplerate: %uHz\n", frame->sample_rate);
printf("ac-channel: %u\n", frame->channels);
printf("f-format: %u\n", frame->format);
}
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
FILE *in_file = (FILE *)opaque;
int read_size = fread(buf, 1, buf_size, in_file);
printf("read_packet read_size:%d, buf_size:%d\n", read_size, buf_size);
if(read_size <=0) {
return AVERROR_EOF;
}
return read_size;
}
static void decode(AVCodecContext *dec_ctx, AVPacket *packet, AVFrame *frame,
FILE *outfile)
{
int ret = 0;
ret = avcodec_send_packet(dec_ctx, packet);
if(ret == AVERROR(EAGAIN)) {
printf("Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
} else if(ret < 0) {
printf("Error submitting the packet to the decoder, err:%s\n",
av_get_err(ret));
return;
}
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return;
} else if (ret < 0) {
printf("Error during decoding\n");
exit(1);
}
if(!packet) {
printf("get flush frame\n");
}
int data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
for(int i = 0; i < frame->nb_samples; i++) {
for(int ch = 0; ch < dec_ctx->channels; ch++) {
fwrite(frame->data[ch] + data_size *i, 1, data_size, outfile);
}
}
}
}
int main(int argc, char **argv)
{
if(argc != 3) {
printf("usage: %s <intput file> <out file>\n", argv[0]);
return -1;
}
const char *in_file_name = argv[1];
const char *out_file_name = argv[2];
FILE *in_file = NULL;
FILE *out_file = NULL;
in_file = fopen(in_file_name, "rb");
if(!in_file) {
printf("open file %s failed\n", in_file_name);
return -1;
}
out_file = fopen(out_file_name, "wb");
if(!out_file) {
printf("open file %s failed\n", out_file_name);
return -1;
}
uint8_t *io_buffer = av_malloc(BUF_SIZE);
AVIOContext *avio_ctx = avio_alloc_context(io_buffer, BUF_SIZE, 0, (void *)in_file, \
read_packet, NULL, NULL);
AVFormatContext *format_ctx = avformat_alloc_context();
format_ctx->pb = avio_ctx;
int ret = avformat_open_input(&format_ctx, NULL, NULL, NULL);
if(ret < 0) {
printf("avformat_open_input failed:%s\n", av_err2str(ret));
return -1;
}
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
if(!codec) {
printf("avcodec_find_decoder failed\n");
return -1;
}
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
if(!codec_ctx) {
printf("avcodec_alloc_context3 failed\n");
return -1;
}
ret = avcodec_open2(codec_ctx, codec, NULL);
if(ret < 0) {
printf("avcodec_open2 failed:%s\n", av_err2str(ret));
return -1;
}
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
while (1) {
ret = av_read_frame(format_ctx, packet);
if(ret < 0) {
printf("av_read_frame failed:%s\n", av_err2str(ret));
break;
}
decode(codec_ctx, packet, frame, out_file);
}
printf("read file finish\n");
decode(codec_ctx, NULL, frame, out_file);
fclose(in_file);
fclose(out_file);
av_free(io_buffer);
av_frame_free(frame);
av_packet_free(packet);
avformat_close_input(&format_ctx);
avcodec_free_context(&codec_ctx);
printf("main finish\n");
return 0;
}