然后解码然后用ffmpeg以相反的顺序重新编码帧

时间:2014-08-21 13:46:44

标签: c video encoding ffmpeg decoding

我对ffmpeg很新,现在我想解码帧并以相反的顺序对其进行编码。我使用this tutorial解码视频,this example对其进行编码。我可以正确解码帧,但是当我重新编码它时,我会得到一个虚拟图像而不是清晰的视频。如何获得实际的反转视频?

static void video_encode_example(const char *filename, int codec_id)
{
    AVCodec *codec;
    AVCodecContext *c= NULL;
    int i, ret, x, y, got_output;
    FILE *f;
    struct SwsContext *sws_ctx = NULL;
    AVFrame *frame;
    AVFrame *frameRGB = NULL;
    AVPacket pkt;
    uint8_t endcode[] = { 0, 0, 1, 0xb7 };

    printf("Encode video file %s\n", filename);

    /* find the mpeg1 video encoder */
    codec = avcodec_find_encoder(codec_id);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }

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

    /* put sample parameters */
    c->bit_rate = 400000;
    /* resolution must be a multiple of two */
    c->width = 352;
    c->height = 288;
    /* frames per second */
    c->time_base = (AVRational){1,25};
    /* 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 */
    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        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;

    /* the image can be allocated by any means and av_image_alloc() is
     * just the most convenient way if av_malloc() is to be used */
    ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
                         c->pix_fmt, 32);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate raw picture buffer\n");
        exit(1);
    }

    /* encode 1 second of video */
    for (i = 0; i < 25; i++) {
        av_init_packet(&pkt);
        pkt.data = NULL;    // packet data will be allocated by the encoder
        pkt.size = 0;

        fflush(stdout);
        /* 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] = 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] = 128 + y + i * 2;
                frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
            }
        }

        frame->pts = i;

        /* encode the image */
        ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
        if (ret < 0) {
            fprintf(stderr, "Error encoding frame\n");
            exit(1);
        }

        if (got_output) {
            // Convert the image from its native format to RGB
            sws_scale
            (
                sws_ctx,
                (uint8_t const * const *)frame->data,
                frame->linesize,
                0,
                c->height,
                frameRGB->data,
                frameRGB->linesize
            );
            printf("Write frame %3d (size=%5d)\n", i, pkt.size);
            fwrite(pkt.data, 1, pkt.size, f);
            av_free_packet(&pkt);
        }
    }

    /* get the delayed frames */
    for (got_output = 1; got_output; i++) {
        fflush(stdout);

        ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
        if (ret < 0) {
            fprintf(stderr, "Error encoding frame\n");
            exit(1);
        }

        if (got_output) {
            printf("Write frame %3d (size=%5d)\n", i, pkt.size);
            fwrite(pkt.data, 1, pkt.size, f);
            av_free_packet(&pkt);
        }
    }

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

    avcodec_close(c);
    av_free(c);
    av_freep(&frame->data[0]);
    av_frame_free(&frame);
    printf("\n");
}

1 个答案:

答案 0 :(得分:0)

假设您的代码示例与视频输入和反向编码无关,但只是&#34;编码样本&#34;。

视频文件由多个部分组成。 首先,您有一个容器格式(例如mkv或avi)。它包含了这个文件中的流的各种信息(subtiles?有多少视频?多个音频流?这样的东西)。 然后你有数据流。 此文件中的视频流是一个数据包列表,由帧中的特定编解码器(例如h264或mpeg4)编码。

在您的代码示例中,您有一个框架列表,并且您使用编解码器对它们进行编码,为您提供数据包列表(我认为它有效,因为它是一个教程代码)。 但是这些数据包被转储到一个没有容器的文件中。因此,如果视频播放器想要阅读它们,我将很难猜出格式是什么。 它被声明为link

中的第一行

您不想直接将数据包转储到文件中,而是希望使用FFmpeg将数据包嵌入容器中,并保存容器。 您有一个所有这个过程here

的示例

最后一件事:如果你想让你的视频按相反的顺序排列,你必须以相反的顺序编码帧,而不是以相反的顺序编码mux数据包。