ffmpeg转化H264,AAC到MP4

分类: C++ 发布时间: 2018-10-28 16:11

由于使用Mpv4无法将H265转化为Mp4,只能使用其他方式进行转化。使用ffmpeg可以将H264和H265转化为Mp4.若要添加上音频,则只需将AAC格式的音频添加上就可以了,亲试可以播放声音。


#ifndef FFMPEG_MP4
#define FFMPEG_MP4

#include

#define __STDC_CONSTANT_MACROS
#define UINT64_C
#define STREAM_FRAME_RATE 25
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */

extern “C”
{
#include <libavutil/opt.h> #include <libavutil/mathematics.h> #include <libavformat/avformat.h> #include <libswresample/swresample.h> }

class FfmpegMp4 :public QThread
{

Q_OBJECT
public:
static FfmpegMp4 * getInstance();
~FfmpegMp4();
int CreateMp4(const char *pszFileName);
void WriteVideo(void* data, int nLen);
void CloseMp4();

private:
static FfmpegMp4 * ffmpegmp4;
explicit FfmpegMp4();

int ptsInc ;
int vi ;
int waitkey ;
AVFormatContext *m_pOc;

int getVopType( const void *p, int len );
AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id);
void open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st);

};

#endif // FFMPEG_MP4

 


#include"ffmpeg_mp4.h"

FfmpegMp4 * FfmpegMp4::ffmpegmp4 =NULL;

FfmpegMp4::FfmpegMp4()
{
ptsInc = 0;
vi = -1;
waitkey = 1;
}

FfmpegMp4::~FfmpegMp4()
{
}

FfmpegMp4 * FfmpegMp4::getInstance()
{
if(ffmpegmp4 == NULL)
ffmpegmp4 = new FfmpegMp4();
return ffmpegmp4;
}

int FfmpegMp4::getVopType( const void *p, int len )
{
if ( !p || 6 >= len )
return -1;

unsigned char *b = (unsigned char*)p;

// Verify NAL marker
if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
{ b++;
if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
return -1;
} // end if

b += 3;

// Verify VOP id
if ( 0xb6 == *b )
{ b++;
return ( *b & 0xc0 ) >> 6;
} // end if

switch( *b )
{ case 0x65 : return 0;
case 0x61 : return 1;
case 0x01 : return 2;
} // end switch

return -1;
}

/* Add an output stream */
AVStream *FfmpegMp4::add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
{
AVCodecContext *c;
AVStream *st;

/* find the encoder */
*codec = avcodec_find_encoder(codec_id);
if (!*codec)
{
printf(“could not find encoder for ‘%s’ \n”, avcodec_get_name(codec_id));
exit(1);
}

st = avformat_new_stream(oc, *codec);
if (!st)
{
printf(“could not allocate stream \n”);
exit(1);
}
st->id = oc->nb_streams-1;
c = st->codec;
vi = st->index;

switch ((*codec)->type)
{
case AVMEDIA_TYPE_AUDIO:
printf(“AVMEDIA_TYPE_AUDIO\n”);
c->sample_fmt = (*codec)->sample_fmts ? (*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
c->bit_rate = 64000;
c->sample_rate = 44100;
c->channels = 2;
break;

case AVMEDIA_TYPE_VIDEO:
printf(“AVMEDIA_TYPE_VIDEO\n”);
c->codec_id = AV_CODEC_ID_H264;
c->bit_rate = 400000;
c->width = 1920;
c->height = 1080;
c->time_base.den = 50;
c->time_base.num = 1;
c->gop_size = 12;
c->pix_fmt = STREAM_PIX_FMT;

//H264
//pCodecCtx->me_range = 16;
//pCodecCtx->max_qdiff = 4;
//pCodecCtx->qcompress = 0.6;
//c->qmin = 10;
//c->qmax = 51;

if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO)
{
c->max_b_frames = 2;
}
if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO)
{
c->mb_decision = 2;
}
break;

default:
break;
}

if (oc->oformat->flags & AVFMT_GLOBALHEADER)
{
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
}

return st;
}

void FfmpegMp4::open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
{
int ret;
AVCodecContext *c = st->codec;

/* open the codec */
ret = avcodec_open2(c, codec, NULL);
if (ret < 0) { printf(“could not open video codec”); //exit(1); } } int FfmpegMp4::CreateMp4(const char *pszFileName) { int ret; // 成功返回0,失败返回1 //const char* pszFileName = “/udisk/vpu.mp4”; AVOutputFormat *fmt; AVCodec *video_codec; AVStream *m_pVideoSt; av_register_all(); avformat_alloc_output_context2(&m_pOc, NULL, NULL, pszFileName); if (!m_pOc) { printf(“Could not deduce output format from file extension: using MPEG. \n”); avformat_alloc_output_context2(&m_pOc, NULL, “mpeg”, pszFileName); } if (!m_pOc) { return 1; } fmt = m_pOc->oformat;

if (fmt->video_codec != AV_CODEC_ID_NONE)
{
printf(“1111111111111111add_stream\n”);
m_pVideoSt = add_stream(m_pOc, &video_codec, fmt->video_codec);
}

if (m_pVideoSt)
{
printf(“1111111111111111open_video\n”);
open_video(m_pOc, video_codec, m_pVideoSt);
}

printf(“==========Output Information==========\n”);

av_dump_format(m_pOc, 0, pszFileName, 1);

printf(“======================================\n”);

/* open the output file, if needed */
if (!(fmt->flags & AVFMT_NOFILE))
{
ret = avio_open(&m_pOc->pb, pszFileName, AVIO_FLAG_WRITE);
if (ret < 0)
{
printf(“could not open %s\n”, pszFileName);
return 1;
}
}

/* Write the stream header, if any */
ret = avformat_write_header(m_pOc, NULL);
if (ret < 0) { printf(“Error occurred when opening output file”); return 1; } } /* write h264 data to mp4 file * 创建mp4文件返回2;写入数据帧返回0 */ void FfmpegMp4::WriteVideo(void* data, int nLen) { int ret; if ( 0 > vi )
{
printf(“vi less than 0”);
//return -1;
}
AVStream *pst = m_pOc->streams[ vi ];
//printf(“vi=====%d\n”,vi);

// Init packet
AVPacket pkt;

// 我的添加,为了计算pts
AVCodecContext *c = pst->codec;

av_init_packet( &pkt );
pkt.flags |= ( 0 >= getVopType( data, nLen ) ) ? AV_PKT_FLAG_KEY : 0;

pkt.stream_index = pst->index;
pkt.data = (uint8_t*)data;
pkt.size = nLen;

// Wait for key frame
if ( waitkey )
if ( 0 == ( pkt.flags & AV_PKT_FLAG_KEY ) )
return ;
else
waitkey = 0;

//pkt.pts = (ptsInc++) * (90000/STREAM_FRAME_RATE);
pkt.pts = av_rescale_q((ptsInc++)*2, pst->codec->time_base,pst->time_base);
//pkt.dts = (ptsInc++) * (90000/STREAM_FRAME_RATE);

// pkt.pts=av_rescale_q_rnd(pkt.pts, pst->time_base,pst->time_base,(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts=av_rescale_q_rnd(pkt.dts, pst->time_base,pst->time_base,(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration,pst->time_base, pst->time_base);
pkt.pos = -1;

// printf(“pkt.size=%d\n”,pkt.size);

ret = av_interleaved_write_frame( m_pOc, &pkt );
if (ret < 0) { printf(“cannot write frame”); } } void FfmpegMp4::CloseMp4() { waitkey = -1; vi = -1; if (m_pOc) av_write_trailer(m_pOc); if (m_pOc && !(m_pOc->oformat->flags & AVFMT_NOFILE))
avio_close(m_pOc->pb);

if (m_pOc)
{
avformat_free_context(m_pOc);
m_pOc = NULL;
}

}

 

扫描下方二维码,关注业余草微信公众号,回复“FFmpeg”关键词,获取 FFmpeg 视频教程!

关注公众号获取视频教程

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!