Anonymous
Как записать необработанный поток H264 в mp4 напрямую, используя ffmpeg
Сообщение
Anonymous » 29 мар 2024, 08:00
Я хочу обернуть H264 Nalus (в кодировке x264) в mp4 с помощью ffmpeg (SDK 2.1), но выходной файл mp4 не удалось воспроизвести. Я не знаю, как установить точки и dts. Вот мой код, использующий код из кадров Raw H264 в контейнере mpegts с использованием libavcodec и muxing.c с сайта
www.ffmpeg.org . В моем потоке H264 нет B-кадра, каждый nalu начинается с 00 00 00 01, поток начинается с sps pps, затем данных h264.
Код: Выделить всё
#include "stdafx.h"
#include
#include
#include "Stream2Mp4.h"
#include
#include
#include
#include
#include
#include
#define STREAM_FRAME_RATE 25
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
static int ptsInc = 0;
static int vi = -1;
static int waitkey = 1;
// < 0 = error
// 0 = I-Frame
// 1 = P-Frame
// 2 = B-Frame
// 3 = S-Frame
int 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;
}
int get_nal_type( void *p, int len )
{
if ( !p || 5 >= 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;
return *b;
}
/* 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 = st->codec;
vi = st->index;
switch ((*codec)->type)
{
case AVMEDIA_TYPE_AUDIO:
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:
c->codec_id = codec_id;
c->bit_rate = 90000;
c->width = 480;
c->height = 354;
c->time_base.den = 15;
c->time_base.num = 1;
c->gop_size = 12;
c->pix_fmt = STREAM_PIX_FMT;
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 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 CreateMp4(AVFormatContext *&m_pOc, void *p, int len)
{
int ret;
const char* pszFileName = "output002.mp4";
AVOutputFormat *fmt;
AVCodec *video_codec;
AVStream *m_pVideoSt;
if (0x67 != get_nal_type(p, len))
{
printf("can not detect nal type");
return -1;
}
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)
{
m_pVideoSt = add_stream(m_pOc, &video_codec, fmt->video_codec);
}
if (m_pVideoSt)
{
open_video(m_pOc, video_codec, m_pVideoSt);
}
av_dump_format(m_pOc, 0, pszFileName, 1);
/* 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': %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*/
void WriteVideo(AVFormatContext *&m_pOc,void* data, int nLen)
{
int ret;
if ( 0 > vi )
{
printf("vi less than 0");
//return -1;
}
AVStream *pst = m_pOc->streams[ vi ];
// Init packet
AVPacket pkt;
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.dts = (ptsInc++) * (90000/STREAM_FRAME_RATE);
ret = av_interleaved_write_frame( m_pOc, &pkt );
if (ret < 0)
{
printf("cannot write frame");
}
}
void CloseMp4(AVFormatContext *&m_pOc)
{
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;
}
}
может ли кто-нибудь мне помочь? Спасибо большое!
Подробнее здесь:
https://stackoverflow.com/questions/233 ... g-directly
1711688454
Anonymous
Я хочу обернуть H264 Nalus (в кодировке x264) в mp4 с помощью ffmpeg (SDK 2.1), но выходной файл mp4 не удалось воспроизвести. Я не знаю, как установить точки и dts. Вот мой код, использующий код из кадров Raw H264 в контейнере mpegts с использованием libavcodec и muxing.c с сайта www.ffmpeg.org. В моем потоке H264 нет B-кадра, каждый nalu начинается с 00 00 00 01, поток начинается с sps pps, затем данных h264. [code]#include "stdafx.h" #include #include #include "Stream2Mp4.h" #include #include #include #include #include #include #define STREAM_FRAME_RATE 25 #define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */ static int ptsInc = 0; static int vi = -1; static int waitkey = 1; // < 0 = error // 0 = I-Frame // 1 = P-Frame // 2 = B-Frame // 3 = S-Frame int 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; } int get_nal_type( void *p, int len ) { if ( !p || 5 >= 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; return *b; } /* 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 = st->codec; vi = st->index; switch ((*codec)->type) { case AVMEDIA_TYPE_AUDIO: 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: c->codec_id = codec_id; c->bit_rate = 90000; c->width = 480; c->height = 354; c->time_base.den = 15; c->time_base.num = 1; c->gop_size = 12; c->pix_fmt = STREAM_PIX_FMT; 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 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 CreateMp4(AVFormatContext *&m_pOc, void *p, int len) { int ret; const char* pszFileName = "output002.mp4"; AVOutputFormat *fmt; AVCodec *video_codec; AVStream *m_pVideoSt; if (0x67 != get_nal_type(p, len)) { printf("can not detect nal type"); return -1; } 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) { m_pVideoSt = add_stream(m_pOc, &video_codec, fmt->video_codec); } if (m_pVideoSt) { open_video(m_pOc, video_codec, m_pVideoSt); } av_dump_format(m_pOc, 0, pszFileName, 1); /* 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': %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*/ void WriteVideo(AVFormatContext *&m_pOc,void* data, int nLen) { int ret; if ( 0 > vi ) { printf("vi less than 0"); //return -1; } AVStream *pst = m_pOc->streams[ vi ]; // Init packet AVPacket pkt; 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.dts = (ptsInc++) * (90000/STREAM_FRAME_RATE); ret = av_interleaved_write_frame( m_pOc, &pkt ); if (ret < 0) { printf("cannot write frame"); } } void CloseMp4(AVFormatContext *&m_pOc) { 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; } } [/code] может ли кто-нибудь мне помочь? Спасибо большое! Подробнее здесь: [url]https://stackoverflow.com/questions/23354915/how-to-write-h264-raw-stream-into-mp4-using-ffmpeg-directly[/url]