Hi Users,

I am trying to write some software that uses the ffv1 encoder, however I am 
unable to produce a valid file using the c api.
I have had success with libx264 and lib264rgb encoders.

I have attached original.c which is a modified version of the example found at 
https://ffmpeg.org/doxygen/trunk/encode_video_8c-example.html
All that is changed is the pixel format to GRAY16 and the population of the 
frame data.
to run it I do:
    ./original "gray.mkv" "ffv1" to load the ffv1 encoder and output a mkv file.

I have attached the output which shows the encoder running and the output from 
ffplay trying to play the file.
The return code from avcodec_recieve_packet() is always AVERROR(EAGAIN).

Is someone able to modify the example code such that it works for ffv1 or tell 
me what I'm mising?

Thanks,
James









/*
 * Copyright (c) 2001 Fabrice Bellard
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
 
/**
 * @file libavcodec encoding video API usage example
 * @example encode_video.c
 *
 * Generate synthetic video data and encode it to an output file.
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#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)
        printf("Send frame %3"PRId64"\n", frame->pts);
 
    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);
        }
 
        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, *codec_name;
    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> <codec name>\n", argv[0]);
        exit(0);
    }
    filename = argv[1];
    codec_name = argv[2];
 
    /* find the mpeg1video encoder */
    codec = avcodec_find_encoder_by_name(codec_name);
    if (!codec) {
        fprintf(stderr, "Codec '%s' not found\n", codec_name);
        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;
    /* resolution must be a multiple of two */
    c->width = 352;
    c->height = 288;
    /* 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;
    c->pix_fmt = AV_PIX_FMT_GRAY16;
 
    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: %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, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate the video frame data\n");
        exit(1);
    }
 
    /* encode 1 second of video */
    for (i = 0; i < 25; i++) {
        fflush(stdout);
 
        /* Make sure the frame data is writable.
           On the first round, the frame is fresh from av_frame_get_buffer()
           and therefore we know it is writable.
           But on the next rounds, encode() will have called
           avcodec_send_frame(), and the codec may have kept a reference to
           the frame in its internal structures, that makes the frame
           unwritable.
           av_frame_make_writable() checks that and allocates a new buffer
           for the frame only if necessary.
         */
        ret = av_frame_make_writable(frame);
        if (ret < 0)
            exit(1);
 
        /* Prepare a dummy image.
           In real code, this is where you would have your own logic for
           filling the frame. FFmpeg does not care what you put in the
           frame.
         */
        for (y = 0; y < c->height; y++) {
            for (x = 0; x < c->width; x++) {
                frame->data[0][y * frame->linesize[0] + x] = 250;
            }
        }
        /* 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 */
        encode(c, frame, pkt, f);
    }
 
    /* flush the encoder */
    encode(c, NULL, pkt, f);
 
    /* Add sequence end code to have a real MPEG file.
       It makes only sense because this tiny examples writes packets
       directly. This is called "elementary stream" and only works for some
       codecs. To create a valid file, you usually need to write packets
       into a proper file format or protocol; see mux.c.
     */
    if (codec->id == AV_CODEC_ID_MPEG1VIDEO || codec->id == AV_CODEC_ID_MPEG2VIDEO)
        fwrite(endcode, 1, sizeof(endcode), f);
    fclose(f);
 
    avcodec_free_context(&c);
    av_frame_free(&frame);
    av_packet_free(&pkt);
 
    return 0;
}
❯ ./original "gray.mkv" "ffv1"
[ffv1 @ 0x8f9700] bits_per_raw_sample > 8, forcing range coder
Send frame   0
Write packet   0 (size= 1210)
Send frame   1
Write packet   1 (size= 1036)
Send frame   2
Write packet   2 (size= 1035)
Send frame   3
Write packet   3 (size= 1035)
Send frame   4
Write packet   4 (size= 1034)
Send frame   5
Write packet   5 (size= 1034)
Send frame   6
Write packet   6 (size= 1034)
Send frame   7
Write packet   7 (size= 1033)
Send frame   8
Write packet   8 (size= 1033)
Send frame   9
Write packet   9 (size= 1033)
Send frame  10
Write packet  10 (size= 1210)
Send frame  11
Write packet  11 (size= 1036)
Send frame  12
Write packet  12 (size= 1035)
Send frame  13
Write packet  13 (size= 1035)
Send frame  14
Write packet  14 (size= 1034)
Send frame  15
Write packet  15 (size= 1034)
Send frame  16
Write packet  16 (size= 1034)
Send frame  17
Write packet  17 (size= 1033)
Send frame  18
Write packet  18 (size= 1033)
Send frame  19
Write packet  19 (size= 1033)
Send frame  20
Write packet  20 (size= 1210)
Send frame  21
Write packet  21 (size= 1036)
Send frame  22
Write packet  22 (size= 1035)
Send frame  23
Write packet  23 (size= 1035)
Send frame  24
Write packet  24 (size= 1034)

////////////////////////////////////////

❯ ffplay gray.mkv
ffplay version 4.4.3 Copyright (c) 2003-2022 the FFmpeg developers
  built with gcc 11 (GCC)
  configuration: --prefix=/usr --bindir=/usr/bin --datadir=/usr/share/ffmpeg 
--docdir=/usr/share/doc/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib64 
--mandir=/usr/share/man --arch=x86_64 --optflags='-O2 -flto=auto 
-ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall 
-Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS 
-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong 
-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic 
-fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' 
--extra-ldflags='-Wl,-z,relro -Wl,--as-needed -Wl,-z,now 
-specs=/usr/lib/rpm/redhat/redhat-hardened-ld 
-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 ' --extra-cflags=' 
-I/usr/include/rav1e' --enable-libopencore-amrnb --enable-libopencore-amrwb 
--enable-libvo-amrwbenc --enable-version3 --enable-bzlib --enable-chromaprint 
--disable-crystalhd --enable-fontconfig --enable-frei0r --enable-gcrypt 
--enable-gnutls --enable-ladspa --enable-libaom --enable-libdav1d 
--enable-libass --enable-libbluray --enable-libbs2b --enable-libcdio 
--enable-libdrm --enable-libjack --enable-libfreetype --enable-libfribidi 
--enable-libgsm --enable-libilbc --enable-libmp3lame --enable-libmysofa 
--enable-nvenc --enable-openal --enable-opencl --enable-opengl 
--enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse 
--enable-librsvg --enable-librav1e --enable-librtmp --enable-librubberband 
--enable-libsmbclient --enable-version3 --enable-libsnappy --enable-libsoxr 
--enable-libspeex --enable-libsrt --enable-libssh --enable-libsvtav1 
--enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libv4l2 
--enable-libvidstab --enable-libvmaf --enable-version3 --enable-vapoursynth 
--enable-libvpx --enable-vulkan --enable-libglslang --enable-libwebp 
--enable-libx264 --enable-libx265 --enable-libxvid --enable-libxml2 
--enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 
--enable-avfilter --enable-avresample --enable-libmodplug --enable-postproc 
--enable-pthreads --disable-static --enable-shared --enable-gpl --disable-debug 
--disable-stripping --shlibdir=/usr/lib64 --enable-lto --enable-libmfx 
--enable-runtime-cpudetect
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
  libpostproc    55.  9.100 / 55.  9.100
[matroska,webm @ 0x7f9c44000c80] Format matroska,webm detected only with low 
score of 1, misdetection possible!
Truncating packet of size 1531168 to 26380
[matroska,webm @ 0x7f9c44000c80] EBML header parsing failed
gray.mkv: Invalid data found when processing input
_______________________________________________
Libav-user mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Reply via email to