Hi everyone in this list. I'm trying to write a simple video split/merge program, that will be part of daemon.<br>I've looked trough api-example.c and output-example.c and written simple program that almost works.<br>
For now i'm just trying to re-encode input file, actual encoding works almost fine but muxing causes problems:<br><br>1) when trying to seek output file with mplayer i get this messages: [mpeg4 @ 0x7fcd7bf12b80]warning: first frame is no keyframe<br>
and playback is broken till next keyframe, like it happens when keyframe is missing/broken.<br>But i've checked CODEC_ID_MPEG4 codec case: kayfarmes are exactly first+n*gop_size (30 in my case)<br>CODEC_ID_H264 is more complex, will describe below<br>
<br>2) both CODEC_ID_H264 and CODEC_ID_MPEG4 give much lower bitrate, than i've set.<br>Desired bitrate: 10Mbps<br>CODEC_ID_H264: 723kbps<br>CODEC_ID_MPEG4: 1142kbps<br><br>3) when trying CODEC_ID_H264 i get error for each frame: [libx264 @ 0xf3e160] non-strictly-monotonic PTS<br>
and additionally first 50 frames are 0-sized, plus post-encode statistics are completely broken.<br>Keyframes for gop size = 30, 200 frames input are this: 49, 100, 143. Looks strange for me.<br><br>I think i've got lack of understanding how muxing should work, especially this PTS magic, so it would be nice if someone<br>
would point what am i doing wrong or not doing, but should.<br><br>Thanks in advance. Here is source code of my program:<br><br><blockquote style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;" class="gmail_quote">
#include <libavcodec/avcodec.h><br>#include <libavformat/avformat.h><br>#include <libswscale/swscale.h><br><br> AVFormatContext *in_ctx;<br> AVFormatContext *out_ctx;<br> AVCodecContext *in_codec_ctx;<br>
AVCodecContext *out_codec_ctx;<br> AVCodec *in_codec;<br> AVCodec *out_codec;<br> AVStream *video_st;<br> int videoStream = -1;<br><br>
<br>int open_input_file(char *filename) {<br><br> // Open video file<br> if(av_open_input_file(&in_ctx, filename, NULL, 0, NULL) != 0)<br> return -1; // Couldn't open file<br><br> // Retrieve stream information<br>
if(av_find_stream_info(in_ctx) < 0)<br> return -1; // Couldn't find stream information<br><br> // Find the first video stream<br> int i;<br> for(i = 0; i < in_ctx->nb_streams; i++)<br> if(in_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {<br>
videoStream = i;<br> break;<br> }<br> if(videoStream == -1)<br> return -1; // Didn't find a video stream<br><br> // Get a pointer to the codec context for the video stream<br>
in_codec_ctx = in_ctx->streams[videoStream]->codec;<br><br> // Find the decoder for the video stream<br> in_codec = avcodec_find_decoder(in_codec_ctx->codec_id);<br> if(in_codec == NULL) {<br> fprintf(stderr, "Unsupported input codec!\n");<br>
return -1; // Codec not found<br> }<br> // Open codec<br> if(avcodec_open(in_codec_ctx, in_codec) < 0)<br> return -1; // Could not open codec<br><br> return 0;<br>}<br><br>int create_out_file(char *filename) {<br>
// Allocate output format context<br> out_ctx = avformat_alloc_context();<br> out_ctx->oformat = av_guess_format(NULL, filename, NULL);<br> if (out_ctx->oformat == NULL)<br> {<br> fprintf(stderr, "Could not guess output format\n");<br>
exit(1);<br> }<br><br> snprintf(out_ctx->filename, sizeof(out_ctx->filename), "%s", filename);<br><br> video_st = av_new_stream(out_ctx, 0);<br> if (!video_st) {<br> fprintf(stderr, "Could not alloc stream\n");<br>
exit(1);<br> }<br><br> out_codec_ctx = video_st->codec;<br> out_codec_ctx->codec_id = CODEC_ID_H264;<br> out_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;<br> out_codec_ctx->bit_rate = 10000000;<br>
//out_codec_ctx->crf = 10;<br> out_codec_ctx->width = in_codec_ctx->width;<br> out_codec_ctx->height = in_codec_ctx->height;<br> out_codec_ctx->time_base.den = in_codec_ctx->time_base.den;<br>
out_codec_ctx->time_base.num = in_codec_ctx->time_base.num;<br> out_codec_ctx->gop_size = 30;<br> out_codec_ctx->pix_fmt = PIX_FMT_YUV420P;<br> out_codec_ctx->thread_count = 4;<br> out_codec_ctx->rc_lookahead = 100;<br>
<br> if(out_ctx->oformat->flags & AVFMT_GLOBALHEADER)<br> out_codec_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;<br><br> out_codec_ctx->flags2 |= CODEC_FLAG2_SSIM;<br> out_codec_ctx->flags |= CODEC_FLAG_PSNR;<br>
<br><br> // Find the encoder for the video stream<br> out_codec = avcodec_find_encoder(out_codec_ctx->codec_id);<br> if(out_codec == NULL) {<br> fprintf(stderr, "Unsupported output codec!\n");<br>
return -1; // Codec not found<br> }<br> // Open codec<br> if(avcodec_open(out_codec_ctx, out_codec) < 0)<br> return -1; // Could not open codec<br><br> avio_open(&out_ctx->pb, filename, AVIO_FLAG_WRITE);<br>
av_write_header(out_ctx);<br><br> return 0;<br>}<br><br>int main(int argc, char **argv) {<br><br> AVFrame *picture;<br> int picture_size;<br> AVFrame *tmp_picture;<br>
int out_size;<br> int frame_count = 0;<br> int frame_finished;<br> AVPacket packet;<br> uint8_t *buffer;<br> struct SwsContext *img_convert_ctx;<br>
int retval;<br><br> av_register_all();<br><br> if (open_input_file(argv[1]))<br> exit(1);<br> if (create_out_file(argv[2]))<br> exit(1);<br><br> av_dump_format(in_ctx, 0, argv[1], 0);<br>
av_dump_format(out_ctx, 0, argv[2], 1);<br><br> //Allocate frame for decoding<br> tmp_picture = avcodec_alloc_frame();<br><br> //Allocate frame fro encoding<br> picture = avcodec_alloc_frame();<br> picture_size = avpicture_get_size(out_codec_ctx->pix_fmt, out_codec_ctx->width, out_codec_ctx->height);<br>
buffer=(uint8_t *)av_malloc(picture_size * sizeof(uint8_t));<br> avpicture_fill((AVPicture *)picture, buffer, out_codec_ctx->pix_fmt, out_codec_ctx->width, out_codec_ctx->height);<br><br> //Crate scaler context<br>
img_convert_ctx = sws_getContext(in_codec_ctx->width, in_codec_ctx->height, in_codec_ctx->pix_fmt,<br> out_codec_ctx->width, out_codec_ctx->height, out_codec_ctx->pix_fmt,<br>
SWS_BICUBIC, NULL, NULL, NULL);<br> if (img_convert_ctx == NULL) {<br> fprintf(stderr, "Cannot initialize the conversion context\n");<br> exit(1);<br> }<br>
<br> av_init_packet(&packet);<br><br> while (av_read_frame(in_ctx, &packet) >= 0) {<br> if(packet.stream_index == videoStream) {<br> frame_count++;<br> //printf("Encoding frame %d\n", frame_count);<br>
//Decode<br> retval = avcodec_decode_video2(in_codec_ctx, tmp_picture, &frame_finished, &packet);<br> if (retval < 0)<br> fprintf(stderr, "Error decoding frame\t%d\n", frame_count);<br>
<br> //Scale<br> retval= sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize,<br> 0, out_codec_ctx->height, picture->data, picture->linesize);<br> if (retval < 1)<br>
fprintf(stderr, "Error scaling frame\t%d\n", frame_count);<br><br> //Encode<br> out_size = avcodec_encode_video(out_codec_ctx, buffer, picture_size, picture);<br> if (out_size <= 0) {<br>
fprintf(stderr, "Error encoding frame\t%d\n", frame_count);<br> } else {<br> //Write<br> if (out_codec_ctx->coded_frame->pts != AV_NOPTS_VALUE)<br> packet.pts = av_rescale_q(out_codec_ctx->coded_frame->pts, out_codec_ctx->time_base, video_st->time_base);<br>
if (out_codec_ctx->coded_frame->key_frame) {<br> packet.flags |= AV_PKT_FLAG_KEY;<br> printf("frame %d is key\n", frame_count);<br> }<br>
packet.stream_index = video_st->index;<br> packet.data = buffer;<br> packet.size = out_size;<br> av_write_frame(out_ctx, &packet);<br> }<br> }<br>
}<br><br> av_write_trailer(out_ctx);<br><br><br> av_free_packet(&packet);<br> av_free(buffer);<br> av_free(picture);<br> av_free(tmp_picture);<br> avcodec_close(in_codec_ctx);<br> avcodec_close(out_codec_ctx);<br>
av_close_input_file(in_ctx);<br> avio_close(out_ctx->pb);<br><br> return 0;<br>}<br></blockquote>