Hello,<br><br>I am trying to capture the X11 screen (using "x11grab") to the mpg output format. This is first step (afterward i will need to add alsa audio), join it into conteiner and at some point send it by socket.<br>
<br>The problem I have is, that the mpg video I received is not syncronized, in other words it looses its timing and is reproduced all in 2 seconds :(.<br><br>Could anybody with experience of this please help me to correct this issue in my code?<br>
<br>Thank you very much,<br>Jiri Novak<br><br>/*==========================================================================================================*/<br>#include <iostream><br>#include <stdio.h><br>#include <assert.h><br>
#include <fstream><br><br>extern "C" {<br>#ifndef INT64_C<br>#define INT64_C(c) (c ## LL)<br>#define UINT64_C(c) (c ## ULL)<br>#endif<br>#include <libavcodec/avcodec.h><br>#include <libswscale/swscale.h><br>
#include <libavformat/avformat.h><br>#include <libavdevice/avdevice.h><br>#include <libavfilter/avfilter.h><br>}<br><br>int main(int argc, char *argv[]) {<br> // register devices, filters and codecs<br>
avdevice_register_all();<br> avfilter_register_all();<br> avcodec_init();<br> avcodec_register_all();<br> av_register_all();<br> <br> // file format, format context<br> AVInputFormat *pInputFormat = av_find_input_format("x11grab");<br>
AVFormatContext *pFormatCtx = avformat_alloc_context(); <br> assert(pInputFormat != NULL && "format unrecognized - pInputFormat is NULL!");<br> assert(pFormatCtx != NULL && "format context could not be allocated - pFormatCtx pointer is NULL!");<br>
<br> // format parameters<br> AVFormatParameters input_video_parameters, *ivp = &input_video_parameters;<br> memset(ivp, 0, sizeof(*ivp));<br> ivp->prealloced_context = 1;<br> ivp->time_base= (AVRational){1,25};<br>
ivp->width = 1400;<br> ivp->height = 1050;<br> <br> // input_format_context, filename, input_format, buffer_size, format_parameters<br> int ret = av_open_input_file(&pFormatCtx, ":0.0", pInputFormat, 0, ivp);<br>
assert(ret >= 0 && "input video file could not be opened!");<br><br> // retrieve stream information<br> ret = av_find_stream_info(pFormatCtx);<br> assert(pFormatCtx >= 0 && "could not retrieve input video stream info!");<br>
<br> // dump information<br> dump_format(pFormatCtx, 0, ":0.0", 0);<br> <br> // find the first video stream<br> int videoStream=-1;<br> for(int i=0; i<pFormatCtx->nb_streams; i++)<br> if(pFormatCtx->streams[i]->codec->codec_type==CODEC_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> AVCodecContext *pCodecCtxDec = pFormatCtx->streams[videoStream]->codec;<br>
<br> // find the decoder for the video stream <br> AVCodec *pCodecDec = avcodec_find_decoder(pCodecCtxDec->codec_id);<br> if(pCodecDec==NULL) {<br> fprintf(stderr, "Unsupported codec!\n");<br> return -1; // Codec not found<br>
}<br> <br> // open codec<br> if (avcodec_open(pCodecCtxDec, pCodecDec)<0)<br> return -1; // Could not open codec<br><br> // alocate codec context<br> AVCodecContext *pCodecCtxEnc = avcodec_alloc_context();<br>
assert(pCodecCtxEnc != NULL && "pCodecCtxEnc pointer is null!");<br> <br> // put sample parameters<br> pCodecCtxEnc->bit_rate = 400000;<br> pCodecCtxEnc->width = 1400;<br> pCodecCtxEnc->height = 1050;<br>
pCodecCtxEnc->time_base= (AVRational){1,25};<br> pCodecCtxEnc->gop_size = 10;<br> pCodecCtxEnc->max_b_frames=1;<br> pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;<br> <br> // find MPEG4 encoder<br> AVCodec *pCodecEnc = avcodec_find_encoder(CODEC_ID_MPEG2VIDEO);<br>
assert(pCodecEnc != NULL && "pCodecEnc pointer is null!");<br> <br> // open the codec<br> int retval = avcodec_open(pCodecCtxEnc, pCodecEnc);<br> assert(retval == 0 && "could not open codec!");<br>
<br> // allocate video frame<br> AVFrame *pFrame = avcodec_alloc_frame();<br><br> // allocate an AVFrame structure<br> AVFrame *pFrameYUV=avcodec_alloc_frame();<br> if(pFrameYUV==NULL)<br> return -1;<br> <br> // calculate the bytes needed for the output image and create buffer for the output image<br>
int nbytes = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height);<br> uint8_t* outbuffer = (uint8_t*)av_malloc(nbytes*10);<br><br> // assign appropriate parts of buffer to image planes in pFrameYUV<br>
avpicture_fill((AVPicture *)pFrameYUV, outbuffer, PIX_FMT_YUV420P, pCodecCtxDec->width, pCodecCtxDec->height); <br><br> int frameFinished;<br> AVPacket packet;<br><br> int i=0;<br> struct SwsContext *img_convert_ctx = NULL;<br>
<br> FILE *f = fopen("output.mpg", "wb");<br> int out_size;<br><br> while (av_read_frame(pFormatCtx, &packet)>=0 && i<50) {<br> fflush(stdout);<br><br> // is this a packet from the video stream<br>
if(packet.stream_index==videoStream) {<br> // Decode video frame<br> avcodec_decode_video2(pCodecCtxDec, pFrame, &frameFinished, &packet);<br> <br> // Did we get a video frame?<br> if(frameFinished) {<br>
if (img_convert_ctx == NULL) {<br> img_convert_ctx = sws_getContext(pCodecCtxDec->width, pCodecCtxDec->height, PIX_FMT_BGRA, pCodecCtxEnc->width, pCodecCtxEnc->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);<br>
<br> if (img_convert_ctx == NULL)<br> std::cerr << "Error" << std::endl;<br> }<br> sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtxEnc->height, pFrameYUV->data, pFrameYUV->linesize);<br>
<br> out_size = avcodec_encode_video(pCodecCtxEnc, outbuffer, nbytes, pFrameYUV);<br> //printf("write frame %3d (size=%5d)\n", i, out_size);<br> fwrite(outbuffer, 1, out_size, f);<br> }<br> }<br>
<br> // Free the packet that was allocated by av_read_frame<br> av_free_packet(&packet);<br> i++;<br> }<br><br> //get the delayed frames<br> for(; out_size; i++) {<br> fflush(stdout);<br> out_size = avcodec_encode_video(pCodecCtxEnc, outbuffer, nbytes, NULL);<br>
//printf("write frame %3d (size=%5d)\n", i, out_size);<br> fwrite(outbuffer, 1, out_size, f);<br> }<br><br> // add sequence end code to have a real mpeg file<br> outbuffer[0] = 0x00;<br> outbuffer[1] = 0x00;<br>
outbuffer[2] = 0x01;<br> outbuffer[3] = 0xb7;<br> fwrite(outbuffer, 1, 4, f);<br> fclose(f);<br> <br> return 0;<br>}<br><br>