c++ - libavcodec, how to transcode video with different frame rates? -


i'm grabbing video frames camera via v4l, , need transcode them in mpeg4 format successively stream them via rtp.

everything "works" there's don't while re-encoding: input stream produces 15fps, while output @ 25fps, , every input frame converted in 1 single video object sequence (i verified simple check on output bitstream). guess receiver correctly parsing mpeg4 bitstream rtp packetization somehow wrong. how supposed split encoded bitstream in 1 or more avpacket ? maybe i'm missing obvious , need b/p frame markers, think i'm not using encode api correctly.

here excerpt of code, based on available ffmpeg samples:

// input frame avframe *picture; // input frame color-space converted avframe *planar; // input format context, video4linux2 avformatcontext *ifmtctx; // output codec context, mpeg4 avcodeccontext *octx; // [ init ] // ... octx->time_base.num = 1; octx->time_base.den = 25; octx->gop_size = 10; octx->max_b_frames = 1; octx->bit_rate = 384000; octx->pix_fmt = pix_fmt_yuv420p;  for(;;) {   // read frame   rdres = av_read_frame( ifmtctx, &pkt );   if ( rdres >= 0 && pkt.size > 0 )   {     // decode     icdcctx->reordered_opaque = pkt.pts;     int decoderes = avcodec_decode_video2( icdcctx, picture, &gotpicture, &pkt );     if ( decoderes >= 0 && gotpicture )     {       // scale / convert color space       avpicture_fill((avpicture *)planar, planarbuf.get(), octx->pix_fmt, octx->width, octx->height);       sws_scale(sws, picture->data, picture->linesize, 0, icdcctx->height, planar->data, planar->linesize);       // encode       bytearray encbuf( 65536 );       int encsize = avcodec_encode_video( octx, encbuf.get(), encbuf.size(), planar );       // happens every gop end       while( encsize == 0 )         encsize = avcodec_encode_video( octx, encbuf.get(), encbuf.size(), 0 );       // send transcoded bitstream result pts       if ( encsize > 0 )         enqueueframe( octx->coded_frame->pts, encbuf.get(), encsize );     }   } } 

most simple solution use 2 threads. first thread things outlined in question (decoding, scaling / color-space conversion, coding). partially transcoded frames written intermediate queue shared second thread. maximum length of queue in particular case (converting lower higher bitrate) 1 frame. second thread reading in loop frames input queue this:

void fpsconverter::threadproc() {  timebeginperiod(1); dword start_time = timegettime(); int frame_counter = 0; while(!shouldfinish()) {     frame *frame = null;     dword time_begin = timegettime();     readinputframe(frame);     writetooutputqueue(frame);     dword time_end = timegettime();     dword next_frame_time = start_time + ++frame_counter * frame_time;     dword time_to_sleep = next_frame_time - time_end;     if (time_to_sleep > 0) {         sleep(time_to_sleep);     } } timeendperiod(1); } 

when cpu power sufficient , higher fidelity , smoothness required compute output frame not 1 frame more frames sort of interpolation (similar techniques used in mpeg codecs). closer output frame time stamp input frame time stamp, more weight should assign particular input frame.


Comments