用FFV1

时间:2018-06-15 12:16:45

标签: ffmpeg libavcodec libav

我在解码用FFV1编解码器编码的灰色图像时遇到问题。 我成功编码了16位灰度图像(使用 avcodec_receive_packet(...)功能)并将 AvPacket 数据保存到文件中。然后我从文件中读取这些数据并尝试解码(使用 avcodec_decode_video2 avcodec_send_packet / avcodec_receive_frame )但没有成功:

  • 当我尝试使用 avcodec_decode_video2 函数解码数据包时出现错误“发生访问冲突,无法写入位置0x0000000000000000”
  • 当我尝试用 avcodec_send_packet / avcodec_receive_frame 函数解码数据包时,我得到一个错误“色度偏移参数7 0无效”

我在编码之后和解码之前比较了数据包,并且所有字段和值看起来都是相同的。我甚至尝试在 avcodec_receive_packet (编码函数)之后解码数据包,但是出现相同的错误。

我使用的是ffmpeg的4.0版本,该程序基于 decode_video.c encode_video.c 示例。 当我使用容器(例如avi)来支持从文件读取/写入编码图像时(基于 demuxing_decoding.c muxing.c examples )我成功编码和解码帧用FFV1。但是我不能使用容器,因为我想编码具有不同分辨率的帧并将几个视频源混合在一起。此外,对于数百张图像,压缩级别显着降低(从2.9降至2.2),这也是非常令人惊讶的。

所以我的问题是如何正确保存/读取(从二进制文件而不是容器)并准备AVPacker以使用FFV1进行解码。

非常感谢任何帮助。

解码代码:

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
}
#pragma warning(disable: 4996)
#define INBUF_SIZE 4096
#define FF_INPUT_BUFFER_PADDING_SIZE 64

uint8_t endcode[4];
AVCodecContext *c, c2;
AVCodec *codec;
int i, ret, x, y;
AVFrame *frame;
AVPacket *pkt, *pkt_temp;

FILE *encodedVideoFile;
AVDictionary *opts = NULL;
uint8_t *video_dst_data[4] = { NULL };
int      video_dst_linesize[4];
int imageSize;
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
/* flush the encoder */
    frame = NULL;
    encode();
    /* add sequence end code to have a real MPEG file */
    //fwrite(endcode, 1, sizeof(endcode), encodedVideoFile);
    fclose(encodedVideoFile);
    avcodec_free_context(&c);
    av_frame_free(&frame);
    av_packet_free(&pkt);
}

void initDecoding(const char *filename)
{
    /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
    memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
    /* find the MPEG-1 video decoder */
    codec = avcodec_find_decoder(AV_CODEC_ID_FFV1);
    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);
    }

    /* resolution must be a multiple of two */
    c->width = 1280;
    c->height = 484;
    /* frames per second */
    c->time_base.den = 1;
    c->time_base.num = 10;
    c->bits_per_raw_sample = 16;

    c->framerate.den = 10;
    c->framerate.num = 1;

    c->pix_fmt = AV_PIX_FMT_GRAY16;

    //Version of FFV1 codec
    c->level = 3;

    /* Init the decoders, with or without reference counting */
    av_dict_set(&opts, "refcounted_frames", 0 ? "1" : "0", 0);
    if ((ret = avcodec_open2(c, codec, &opts)) < 0) {
        return;
    }

    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }

    ret = av_image_alloc(video_dst_data, video_dst_linesize,
        c->width, c->height, c->pix_fmt, 4);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate raw video buffer\n");
    }

    encodedVideoFile = fopen(filename, "rb");
    if (!encodedVideoFile) {
        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);
    }

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

void closeDecoding()
{
    fclose(encodedVideoFile);
    av_parser_close(parser);
    avcodec_free_context(&c);
    av_frame_free(&frame);
    av_packet_free(&pkt);
}

void decodePacket()
{
    size_t data_size;
    int *got_frame = 0;

    read_packt_from_file(pkt, encodedVideoFile);        

    ret = av_frame_is_writable(frame);

    //First decoding function
    /*ret = avcodec_decode_video2(c, frame, got_frame, pkt);
    if (ret < 0) {
        fprintf(stderr, "Error decoding video frame (%s)\n");

    }*/

    ret = avcodec_send_packet(c, pkt);
    if (ret < 0) {
        fprintf(stderr, "Error sending a packet for decoding\n");
        exit(1);
    }
    while (ret >= 0) {
        ret = avcodec_receive_frame(c, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during decoding\n");
            exit(1);
        }
        printf("saving frame %3d\n", c->frame_number);

        fflush(stdout);

    }

}

size_t read_packt_from_file(AVPacket *packet, FILE *file)
{
    size_t ret = 0;
    int size;
    uint8_t * data;
    //av_packet_from_data
    ret = fread(packet, sizeof(AVPacket), 1, file);
    size = packet->size;
    data = new uint8_t[size];
    ret = fread(data, size, 1, file);
    av_new_packet(packet, size);
    av_packet_from_data(packet, data, size);

    return ret;
}
//To write encoded AVPacket
size_t write_packt_to_file(AVPacket *packet, FILE *file)
{
    size_t ret = 0;
    ret = fwrite(packet, sizeof(AVPacket), 1, file);
    ret = fwrite(packet->data, packet->size, 1, file);
    if (packet->buf) {
        fwrite(packet->buf->data, packet->buf->size, 1, file);
    }
    fflush(file);
    return ret;
}

0 个答案:

没有答案