0

After my previous question, I found codes from here to create videos in C++ using avcodec of ffmpeg libraries.

I have modified this code to comply with C++. Everything is fine and it creates mp4 videos. Except for the output video opens with some video managers and does not open with some others.

E.g. I can open it on Linux by totem (the slider does not allow back and forth anyway). But VLC (on the same Linux machine) does not open this file. Probably, there will be similar problem in windows.

Is there any missing process for this code causing this problem?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>

extern "C" {
    #include <libavcodec/avcodec.h>
    #include <libavutil/opt.h>
    #include <libavutil/imgutils.h>
}

static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
                   FILE *outfile)
{
    int ret;

    /* send the frame to the encoder */
    if (frame)
        std::cout<<"Send frame "<<(frame->pts)<<std::endl;

    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }

    while (ret >= 0) {
        ret = avcodec_receive_packet(enc_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during encoding\n");
            exit(1);
        }

        std::cout<<"Write packet "<<(pkt->pts)<<" (size="<<(pkt->size)<<")"<<std::endl;
        // printf("Write packet %3" PRId64" (size=%5d)\n", pkt->pts, pkt->size);
        fwrite(pkt->data, 1, pkt->size, outfile);
        av_packet_unref(pkt);
    }
}

int main(int argc, char **argv)
{
    const char *filename;
    const AVCodec *codec;
    AVCodecContext *c= NULL;
    int i, ret, x, y;
    FILE *f;
    AVFrame *frame;
    AVPacket *pkt;
    uint8_t endcode[] = { 0, 0, 1, 0xb7 };

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <output file>\n", argv[0]);
        exit(0);
    }
    filename = argv[1];
    std::string codec_name = "mpeg4";

    avcodec_register_all();

    /* find the mpeg1video encoder */
    codec = avcodec_find_encoder_by_name(codec_name.c_str());
    if (!codec) {
        fprintf(stderr, "Codec '%s' not found\n", codec_name.c_str());
        exit(1);
    }

    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }

    pkt = av_packet_alloc();
    if (!pkt)
        exit(1);

    /* put sample parameters */
    // c->bit_rate = 400000;
    c->bit_rate = 4000000;
    /* resolution must be a multiple of two */
    // c->width = 352;
    // c->height = 288;
    c->width = 640;
    c->height = 480;
    /* frames per second */
    c->time_base = (AVRational){1, 25};
    c->framerate = (AVRational){25, 1};

    /* emit one intra frame every ten frames
     * check frame pict_type before passing frame
     * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
     * then gop_size is ignored and the output of encoder
     * will always be I frame irrespective to gop_size
     */
    c->gop_size = 10;
    c->max_b_frames = 1;
    c->pix_fmt = AV_PIX_FMT_YUV420P;

    if (codec->id == AV_CODEC_ID_H264)
        av_opt_set(c->priv_data, "preset", "slow", 0);

    /* open it */
    ret = avcodec_open2(c, codec, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not open codec\n");
        // fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
        exit(1);
    }

    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }

    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }
    frame->format = c->pix_fmt;
    frame->width  = c->width;
    frame->height = c->height;

    ret = av_frame_get_buffer(frame, 32);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate the video frame data\n");
        exit(1);
    }

    /* encode 10 second of video */
    for (i = 0; i < 250; i++) {
        fflush(stdout);

        /* make sure the frame data is writable */
        ret = av_frame_make_writable(frame);
        if (ret < 0)
            exit(1);

        /* prepare a dummy image */
        /* Y */
        for (y = 0; y < c->height; y++) {
            for (x = 0; x < c->width; x++) {
                frame->data[0][y * frame->linesize[0] + x] = uint8_t(x + y + i * 3);
            }
        }

        /* Cb and Cr */
        for (y = 0; y < c->height/2; y++) {
            for (x = 0; x < c->width/2; x++) {
                frame->data[1][y * frame->linesize[1] + x] = uint8_t(128 + y + i * 2);
                frame->data[2][y * frame->linesize[2] + x] = uint8_t(64 + x + i * 5);
            }
        }

        frame->pts = i;

        /* encode the image */
        encode(c, frame, pkt, f);
    }

    /* flush the encoder */
    encode(c, NULL, pkt, f);

    /* add sequence end code to have a real MPEG file */
    fwrite(endcode, 1, sizeof(endcode), f);
    fclose(f);

    avcodec_free_context(&c);
    av_frame_free(&frame);
    av_packet_free(&pkt);

    return 0;
}

build:

g++ -I ./FFmpeg/ video.cpp -L ./fflibs -lavdevice -lavfilter -lavformat -lavcodec -lrt -ldl -lXfixes -lXext -lX11 -lasound -lSDL -lz -lrt -lswresample -lswscale -lavutil -lm -llzma -lbz2 -lswresample -lpthread

run

./a.out myvideo.mp4

This video will be fine if converted in bash via

ffmpeg -i myvideo.mp4 out1.mp4

But I look for a method to fix it from the code.

Generated video played on totem (Ubuntu):

c++ ffmpeg avcodec

Video after conversion:

converted

ar2015
  • 5,558
  • 8
  • 53
  • 110
  • See this muxing example and set your pts properly https://ffmpeg.org/doxygen/2.8/muxing_8c-example.html – Ankur Nov 18 '17 at 05:27
  • @Ankur, I dont understand what is wrong with my pts. – ar2015 Nov 18 '17 at 06:39
  • You are incrementing pts by 1 . It is actually a relation between codec time base and stream time base. There are multiple ways to set pts. But this answer should point you in the right direction. https://stackoverflow.com/questions/13595288/understanding-pts-and-dts-in-video-frames – Ankur Nov 18 '17 at 06:42
  • I am new to frames, videos and codecs. I still did not catch what to do. Should I scale an integer? sounds unrealistic. – ar2015 Nov 18 '17 at 06:46
  • Read the answer in the link and muxing example. They explain it better – Ankur Nov 18 '17 at 06:50
  • `frame->pts = codec->pts` ?? – ar2015 Nov 18 '17 at 06:56
  • frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base); } Try setting your pts like this. Where video_st is your stream. – Ankur Nov 18 '17 at 10:41
  • Codec time base is avrational 1/framerate. Stream timebase can be anything like 1/90000 for voip. Or 1/128000. Depends on the stream – Ankur Nov 18 '17 at 10:43
  • @Ankur, Many thanks. It requires a stream. I am wondering `AVStream *outStream =???`. The line `AVStream *outStream = avformat_new_stream(c, codec);` does give me error: cannot convert ‘AVCodecContext*’ to ‘AVFormatContext* – ar2015 Nov 18 '17 at 15:36
  • You may not want stream . Those structures are avrational – Ankur Nov 18 '17 at 15:58
  • @Ankur, I use `frame->pts += av_rescale_q(1, c->time_base, c->time_base);` which compiles fine but it gives me `[mpeg4 @ 0x36f7c20] time_incr 18077809191891763200 too large` shouldn't I run `av_rescale_q` to add value to `pkt.pts` like [here](https://github.com/rvs/ffmpeg/blob/master/libavformat/output-example.c)? – ar2015 Nov 18 '17 at 16:25
  • In place of second c->timebase use avrational {1,128000} – Ankur Nov 18 '17 at 17:13
  • @Ankur, used `frame->pts += av_rescale_q(1, c->time_base, (AVRational){1,128000});` which compiled fine but in run time gave me so many `[mpeg4 @ 0x2cd2c20] time_incr 18077809191891763610 too large`, then `[mpeg4 @ 0x39cec20] Internal error, picture buffer overflow` and finally `Aborted (core dumped)` – ar2015 Nov 18 '17 at 23:48
  • Try 12800. I don't remember the correct value – Ankur Nov 19 '17 at 03:12
  • Then try muxing example. Comment the audio part – Ankur Nov 19 '17 at 07:09
  • @Ankur Please if you can throw some light on this as well https://stackoverflow.com/questions/48055979/mux-audio-and-video-ffmpeg-c – Valgrind1691 Jan 04 '18 at 08:48
  • @ar2015 Did you get this resolved? – Valgrind1691 Jan 04 '18 at 09:12
  • @Valgrind1691, I still use ffmpeg to convert the video! Then I open it. – ar2015 Jan 05 '18 at 02:02
  • @ar2015 Means you got this working? – Valgrind1691 Jan 05 '18 at 04:50
  • @Valgrind1691, Means C code does not work. I just get around it by ffmpeg in the linux shell not the C library of ffmpeg. – ar2015 Jan 05 '18 at 08:35
  • okay, seems you went the executable way – Valgrind1691 Jan 05 '18 at 08:36

0 Answers0