[FFmpeg-trac] #6720(avformat:new): Failure to write last packet to stream

FFmpeg trac at avcodec.org
Fri Oct 6 18:14:15 EEST 2017


#6720: Failure to write last packet to stream
-------------------------------------+------------------------------------
             Reporter:  pixelmyr     |                    Owner:
                 Type:  defect       |                   Status:  new
             Priority:  normal       |                Component:  avformat
              Version:  unspecified  |               Resolution:
             Keywords:  avio, muxer  |               Blocked By:
             Blocking:               |  Reproduced by developer:  0
Analyzed by developer:  0            |
-------------------------------------+------------------------------------

Comment (by pixelmyr):

 Hi all,

 I made a simpler demo with none of my abstraction code. You'll find it
 below:
 {{{
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <math.h>

 #include <libavutil/avassert.h>
 #include <libavutil/channel_layout.h>
 #include <libavutil/opt.h>
 #include <libavutil/mathematics.h>
 #include <libavutil/timestamp.h>
 #include <libavformat/avformat.h>
 #include <libswscale/swscale.h>
 #include <libswresample/swresample.h>

 #define FRAME_RATE 15

 #define WIDTH 2040
 #define HEIGHT 1536
 #define BYTES_PER_PIXEL 3
 #define BITS_PER_PIXEL 24

 #define BUFFER_SIZE 131072

 int IOWrite(void* opaque, unsigned char* buf, int bufSize)
 {
     printf("Wrote %d bytes.\n", bufSize);
     return bufSize;
 }

 int main()
 {
     av_register_all();

     AVFormatContext* outputFormatContext;
     avformat_alloc_output_context2(&outputFormatContext, NULL, "webm",
 NULL);

     AVOutputFormat* outputFormat = outputFormatContext->oformat;

     AVStream* stream = avformat_new_stream(outputFormatContext, NULL);
     stream->id = outputFormatContext->nb_streams - 1;

     AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_VP9);
     AVCodecContext* encodingContext = avcodec_alloc_context3(codec);
     encodingContext->width = WIDTH;
     encodingContext->height = HEIGHT;
     encodingContext->time_base = (AVRational){ 1, FRAME_RATE };
     encodingContext->pix_fmt = AV_PIX_FMT_YUV420P;

     avcodec_open2(encodingContext, codec, NULL);

     stream->time_base = encodingContext->time_base;
     encodingContext->framerate = av_inv_q(encodingContext->time_base);
     stream->avg_frame_rate = encodingContext->framerate;

     if (outputFormat->flags & AVFMT_GLOBALHEADER)
         encodingContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

     avcodec_parameters_from_context(stream->codecpar, encodingContext);

     unsigned char* buf = av_malloc(BUFFER_SIZE);

     AVIOContext* ioContext = avio_alloc_context(buf, BUFFER_SIZE, 1, NULL,
         NULL, IOWrite, NULL);

     outputFormatContext->pb = ioContext;
     outputFormatContext->flags |= AVFMT_FLAG_CUSTOM_IO;

     avformat_write_header(outputFormatContext, NULL);

     struct SwsContext* imageConverter = sws_getContext(WIDTH, HEIGHT,
 AV_PIX_FMT_BGR24, WIDTH, HEIGHT, AV_PIX_FMT_YUV420P, 0, NULL, NULL, NULL);

     AVFrame* yuvFrame = av_frame_alloc();
     // Set up the YUV destination frame
     yuvFrame->linesize[0] = WIDTH;
     yuvFrame->linesize[1] = WIDTH / 2;
     yuvFrame->linesize[2] = WIDTH / 2;

     int ySize = yuvFrame->linesize[0] * HEIGHT;
     int uSize = yuvFrame->linesize[1] * HEIGHT / 2;

     yuvFrame->format = AV_PIX_FMT_YUV420P;
     yuvFrame->width = WIDTH;
     yuvFrame->height = HEIGHT;

     // Allocate the data
     av_frame_get_buffer(yuvFrame, 32);

     AVFrame* sourceFrame = av_frame_alloc();

     unsigned long int pts = 0;

     int numFrames = 1;
     for (int i = 0; i < numFrames; ++i)
     {
         FILE* f;

         char buf[256];
         sprintf_s(buf, 256, "D:/output/Frame_%d.bmp", i);

         fopen_s(&f, buf, "rb");

         fseek(f, 0, SEEK_END);
         int bmpSize = ftell(f);
         fseek(f, 0, SEEK_SET);

         unsigned char* bmp = (unsigned char*)malloc(bmpSize);
         fread(bmp, 1, bmpSize, f);

         fclose(f);

         sourceFrame->data[0] = bmp;
         sourceFrame->data[1] = bmp + 1;
         sourceFrame->data[2] = bmp + 2;

         sourceFrame->linesize[0] = WIDTH * BYTES_PER_PIXEL;
         sourceFrame->linesize[1] = WIDTH * BYTES_PER_PIXEL;
         sourceFrame->linesize[2] = WIDTH * BYTES_PER_PIXEL;

         av_frame_make_writable(yuvFrame);

         sws_scale(imageConverter, sourceFrame->data,
 sourceFrame->linesize,
             0, HEIGHT, yuvFrame->data, yuvFrame->linesize);

         yuvFrame->pts = pts++;
         avcodec_send_frame(encodingContext, yuvFrame);

         free(bmp);
     }

     // Force a flush
     avcodec_send_frame(encodingContext, NULL);

     // grab every packet
     AVPacket p = { 0 };
     while (1)
     {
         av_packet_unref(&p);
         av_init_packet(&p);
         int result = avcodec_receive_packet(encodingContext, &p);
         if (result < 0)
         {
             break;
         }
         av_packet_rescale_ts(&p, encodingContext->time_base,
 stream->time_base);
         p.stream_index = stream->index;
         av_interleaved_write_frame(outputFormatContext, &p);
     }

     avio_flush(outputFormatContext->pb);

     printf("Press any key to continue...");
     getchar();

     return 0;
 }
 }}}

 In the case of 1 packet, the callback only fired for the WebM header, with
 an output of `Wrote 419 bytes.`.

 When I played with the `numFrames` variable, I found that my original
 assumption was false. The frames definitely do get written, but the buffer
 is not necessarily flushed. I receive as many packets out as frames in,
 but they don't get written to the buffer.

 I hope this helps!

--
Ticket URL: <https://trac.ffmpeg.org/ticket/6720#comment:1>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list