#include "stdafx.h"
#include "FFMPEG_MP4.h"
int ptsInc = 0;
int waitkey = 1;;
int STREAM_FRAME_RATE = 25;
AVFormatContext* m_pOc;
int vi;
bool isIdrFrame2(uint8_t* buf, int len){
switch (buf[0] & 0x1f){
case 7: // SPS
return true;
case 8: // PPS
return true;
case 5:
return true;
case 1:
return false;
default:
return false;
break;
}
return false;
}
bool isIdrFrame1(uint8_t* buf, int size){
//主要是解析idr前面的sps pps
// static bool found = false;
// if(found){ return true;}
int last = 0;
for (int i = 2; i <= size; ++i){
if (i == size) {
if (last) {
bool ret = isIdrFrame2(buf + last, i - last);
if (ret) {
//found = true;
return true;
}
}
}
else if (buf[i - 2] == 0x00 && buf[i - 1] == 0x00 && buf[i] == 0x01) {
if (last) {
int size = i - last - 3;
if (buf[i - 3]) ++size;
bool ret = isIdrFrame2(buf + last, size);
if (ret) {
//found = true;
return true;
}
}
last = i + 1;
}
}
return false;
}
/* Add an output stream /
AVStream *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 = avcodec_alloc_context3(NULL);
if (c == NULL){
printf("Could not allocate AVCodecContext\n");
}
avcodec_parameters_to_context(c, st->codecpar);
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 = 0;
c->width = 1080;
c->height = 720;
c->time_base.den = 50;
c->time_base.num = 1;
c->gop_size = 1;
c->pix_fmt = AV_PIX_FMT_YUV420P;
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 |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
return st;
}
void open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
{
int ret;
AVCodecContext *c;
c = avcodec_alloc_context3(NULL);
if (c == NULL){
printf("Could not allocate AVCodecContext\n");
}
avcodec_parameters_to_context(c, st->codecpar);
/* open the codec */
ret = avcodec_open2(c, codec, NULL);
if (ret < 0)
{
printf("could not open video codec");
//exit(1);
}
}
//testing purpose of indicate the file name and file path
//int CreateMp4(const char* filename)
void CreateMP4()
{
int ret; // 成功返回0,失败返回1
const char* pszFileName = "../1.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;
}
//return 0;
}
/ write h264 data to mp4 file
-
创建mp4文件返回2;写入数据帧返回0 /
void WriteVideo(void data, int nLen)
{
int ret;
if (0 > vi)
{
printf("vi less than 0\n");
//return -1;
}
AVStream *pst = m_pOc->streams[vi];
//printf("vi=====%d\n",vi);
// Init packet
AVPacket pkt;
// caculate pst
AVCodecContext *c;
c = avcodec_alloc_context3(NULL);
if (c == NULL){
printf("Could not allocate AVCodecContext\n");}
avcodec_parameters_to_context(c, pst->codecpar);
av_init_packet(&pkt);
int isI = isIdrFrame1((uint8_t*)data, nLen);
printf("isIFrame is %d\n", isI);
pkt.flags |= isI ? 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 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;
}
}
一共是报了两个声明被否决 一个是 'av_register_all': 被声明为已否决 另一个是 'AVStream::codec': 被声明为已否决。
这个代码是从https://www.jianshu.com/p/e62dc6928941 照搬的,我这边的FFMPEG的库是4.1版本 因为小弟才刚开始学习 不是很清楚他的实现思路 更不知道 如何解决这两个声明被否决的问题, 请问有大神能够指导一下吗?
'AVStream::codec': 被声明为已否决:指向的是这一句:pkt.pts = av_rescale_q((ptsInc++) * 2, pst->codec->time_base, pst->time_base);