[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