问题
What I'm doing is on an IOS app with Xcode 7.3.
I got h264 data from an ip camera using UDP,the data can be decoded and displayed rightly (decoded by ffmpeg). Now I want to mux the raw H264 data to an mp4 file(some users may want to record what they are watching on his cell-phone), using ffmpeg. Nothing wrong happened when the code is running, and the result file can be played normally with QuickTime on my computer. But when played on iphone with iphone's default video player, it can't be played normally.Here is my code.
Wish someone could tell me what should I do, thanks!
init
AVFormatContext *formatContext;
AVOutputFormat *outputFormat;
AVStream *video_st;
int STREAM_FRAME_RATE = 15;
unsigned long video_PTS;
int initRecorder(char *fileName, int width, int height) {
video_st = NULL;
video_PTS = 0;
av_register_all();
outputFormat = av_guess_format(NULL, fileName, NULL);
if (!outputFormat) {
zj_printf("av_guess_format -> fail\n");
return -1;
}
outputFormat->video_codec = AV_CODEC_ID_H264;
avformat_alloc_output_context2(&formatContext, NULL, NULL, fileName);
if (!formatContext) {
zj_printf("avformat_alloc_context -> fail\n");
return -2;
}
formatContext->oformat = outputFormat;
strcpy(formatContext->filename, fileName);
video_st = add_video_stream(formatContext, outputFormat, width, height);
if (!video_st || open_video(formatContext, video_st)) {
zj_printf("Could not open video codec\n");
return -3;
}
av_dump_format(formatContext, 0, fileName, 1);
if (!(outputFormat->flags & AVFMT_NOFILE)) {
if (avio_open(&formatContext->pb, fileName, AVIO_FLAG_READ_WRITE) < 0) {
zj_printf("could not open file: %s\n", fileName);
return -7;
}
}
/* write the stream header, if any */
if (avformat_write_header(formatContext, NULL)) {
zj_printf("avformat_write_header -> fail\n");
}
return 0;
}
add video stream and open
static AVStream * add_video_stream(AVFormatContext *pFormatContext, AVOutputFormat *pOutputFormat, int wight, int height) {
AVStream *stream = avformat_new_stream(pFormatContext, NULL);
if (!stream) {
zj_fprintf(stderr, "Could not alloc stream\n");
return NULL;
}
stream->id = 0;
AVCodecContext *codecContext = stream->codec;
codecContext->codec_id = pOutputFormat->video_codec;
codecContext->codec_type = AVMEDIA_TYPE_VIDEO;
/* resolution must be a multiple of two */
codecContext->width = wight;
codecContext->height = height;
/* time base: this is the fundamental unit of time (in seconds) in terms
of which frame timestamps are represented. for fixed-fps content,
timebase should be 1/framerate and timestamp increments should be
identically 1. */
if (wight==1280 && height == 720) {
codecContext->bit_rate = 512000;
STREAM_FRAME_RATE = 15;
} else {
codecContext->bit_rate = 384000;
STREAM_FRAME_RATE = 20;
}
codecContext->time_base = (AVRational){1,STREAM_FRAME_RATE};
stream->time_base = (AVRational){1,STREAM_FRAME_RATE};
codecContext->max_b_frames = 0;
codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
// these are the encoding params, here we do not need them
// codecContext->gop_size = 12; //10
// codecContext->me_range = 16;
// codecContext->max_qdiff = 4;
// codecContext->qmin = 10;
// codecContext->qmax = 31;
if (pFormatContext->oformat->flags & AVFMT_GLOBALHEADER)
codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
return stream;
}
static int open_video(AVFormatContext *pFormatContext, AVStream *pStream) {
/* find the video encoder */
AVCodec *codec = avcodec_find_encoder(pStream->codec->codec_id);
if (!codec) {
return -1;
}
/* open the codec */
if (avcodec_open2(pStream->codec, codec, NULL)) {
return -2;
}
return 0;
}
write video frame
static int write_video_frame(char *buffer, int size) {
int ret = 0;
if (size > 0) {
AVPacket mAVPacket;
av_init_packet(&mAVPacket);
mAVPacket.flags = isIFrame(buffer, size);
mAVPacket.stream_index = video_st->index;
mAVPacket.data = buffer;
mAVPacket.size = size;
mAVPacket.pts = video_PTS;
mAVPacket.dts = video_PTS;
video_PTS += 1;
mAVPacket.pts = av_rescale_q_rnd(mAVPacket.pts, video_st->codec->time_base, video_st->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
mAVPacket.dts = av_rescale_q_rnd(mAVPacket.dts, video_st->codec->time_base, video_st->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
mAVPacket.duration = 0;
mAVPacket.pos = -1;
ret = av_interleaved_write_frame(formatContext, &mAVPacket);
}
av_packet_unref(&mAVPacket);
} else {
ret = -2;
}
if (ret != 0) {
zj_printf("av_write_frame error:%d\n", ret);
}
return ret;
}
set the extradata in the codec context
unsigned char sps_pps[23] = {0x00, 0x00, 0x00, 0x01, 0x67, 0x64, 0x00, 0x29, 0xac, 0x1b, 0x1a, 0xc1, 0xe0, 0x51, 0x90, 0x00, 0x00, 0x00, 0x01, 0x68, 0xea, 0x43, 0xcb};
codecContext->extradata_size = 23;
codecContext->extradata = av_malloc(23 + AV_INPUT_BUFFER_PADDING_SIZE);
if (codecContext->extradata == NULL) {
printf("could not av_malloc the video params extradata!\n");
return -1;
}
memcpy(codecContext->extradata, sps_pps, 23);
回答1:
Your bitstream format is annex b. You must convert to the MP4 format by replacing start codes with nal length values. You must also populate the extradata in the codeccontext. Possible Locations for Sequence/Picture Parameter Set(s) for H.264 Stream
来源:https://stackoverflow.com/questions/39012402/mux-raw-h-264-to-an-mp4-file-some-odd-errors