mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-12 19:18:44 +02:00
b43b95f478
This was left over from an earlier version which created the new packet inside the current frame structure. Now it just leaks an unused packet, so remove the allocation entirely.
408 lines
12 KiB
C
408 lines
12 KiB
C
/*
|
|
* This file is part of Libav.
|
|
*
|
|
* Libav is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* Libav is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with Libav; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "libavutil/avassert.h"
|
|
#include "libavutil/intmath.h"
|
|
#include "libavutil/log.h"
|
|
#include "libavutil/mem.h"
|
|
#include "libavutil/opt.h"
|
|
|
|
#include "bitstream.h"
|
|
#include "bsf.h"
|
|
#include "put_bits.h"
|
|
|
|
#define FRAME_SLOTS 8
|
|
|
|
typedef struct VP9RawReorderFrame {
|
|
AVPacket *packet;
|
|
int needs_output;
|
|
int needs_display;
|
|
|
|
int64_t pts;
|
|
int64_t sequence;
|
|
unsigned int slots;
|
|
|
|
unsigned int profile;
|
|
|
|
unsigned int show_existing_frame;
|
|
unsigned int frame_to_show;
|
|
|
|
unsigned int frame_type;
|
|
unsigned int show_frame;
|
|
unsigned int refresh_frame_flags;
|
|
} VP9RawReorderFrame;
|
|
|
|
typedef struct VP9RawReorderContext {
|
|
int64_t sequence;
|
|
VP9RawReorderFrame *slot[FRAME_SLOTS];
|
|
VP9RawReorderFrame *next_frame;
|
|
} VP9RawReorderContext;
|
|
|
|
static void vp9_raw_reorder_frame_free(VP9RawReorderFrame **frame)
|
|
{
|
|
if (*frame)
|
|
av_packet_free(&(*frame)->packet);
|
|
av_freep(frame);
|
|
}
|
|
|
|
static void vp9_raw_reorder_clear_slot(VP9RawReorderContext *ctx, int s)
|
|
{
|
|
if (ctx->slot[s]) {
|
|
ctx->slot[s]->slots &= ~(1 << s);
|
|
if (ctx->slot[s]->slots == 0)
|
|
vp9_raw_reorder_frame_free(&ctx->slot[s]);
|
|
else
|
|
ctx->slot[s] = NULL;
|
|
}
|
|
}
|
|
|
|
static int vp9_raw_reorder_frame_parse(AVBSFContext *bsf, VP9RawReorderFrame *frame)
|
|
{
|
|
BitstreamContext bc;
|
|
int err;
|
|
|
|
unsigned int frame_marker;
|
|
unsigned int profile_low_bit, profile_high_bit, reserved_zero;
|
|
unsigned int error_resilient_mode;
|
|
unsigned int frame_sync_code;
|
|
|
|
err = bitstream_init8(&bc, frame->packet->data, frame->packet->size);
|
|
if (err)
|
|
return err;
|
|
|
|
frame_marker = bitstream_read(&bc, 2);
|
|
if (frame_marker != 2) {
|
|
av_log(bsf, AV_LOG_ERROR, "Invalid frame marker: %u.\n",
|
|
frame_marker);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
profile_low_bit = bitstream_read_bit(&bc);
|
|
profile_high_bit = bitstream_read_bit(&bc);
|
|
frame->profile = (profile_high_bit << 1) | profile_low_bit;
|
|
if (frame->profile == 3) {
|
|
reserved_zero = bitstream_read_bit(&bc);
|
|
if (reserved_zero != 0) {
|
|
av_log(bsf, AV_LOG_ERROR, "Profile reserved_zero bit set: "
|
|
"unsupported profile or invalid bitstream.\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
}
|
|
|
|
frame->show_existing_frame = bitstream_read_bit(&bc);
|
|
if (frame->show_existing_frame) {
|
|
frame->frame_to_show = bitstream_read(&bc, 3);
|
|
return 0;
|
|
}
|
|
|
|
frame->frame_type = bitstream_read_bit(&bc);
|
|
frame->show_frame = bitstream_read_bit(&bc);
|
|
error_resilient_mode = bitstream_read_bit(&bc);
|
|
|
|
if (frame->frame_type == 0) {
|
|
frame_sync_code = bitstream_read(&bc, 24);
|
|
if (frame_sync_code != 0x498342) {
|
|
av_log(bsf, AV_LOG_ERROR, "Invalid frame sync code: %06x.\n",
|
|
frame_sync_code);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
frame->refresh_frame_flags = 0xff;
|
|
} else {
|
|
unsigned int intra_only;
|
|
|
|
if (frame->show_frame == 0)
|
|
intra_only = bitstream_read_bit(&bc);
|
|
else
|
|
intra_only = 0;
|
|
if (error_resilient_mode == 0) {
|
|
// reset_frame_context
|
|
bitstream_skip(&bc, 2);
|
|
}
|
|
if (intra_only) {
|
|
frame_sync_code = bitstream_read(&bc, 24);
|
|
if (frame_sync_code != 0x498342) {
|
|
av_log(bsf, AV_LOG_ERROR, "Invalid frame sync code: "
|
|
"%06x.\n", frame_sync_code);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
if (frame->profile > 0) {
|
|
unsigned int color_space;
|
|
if (frame->profile >= 2) {
|
|
// ten_or_twelve_bit
|
|
bitstream_skip(&bc, 1);
|
|
}
|
|
color_space = bitstream_read(&bc, 3);
|
|
if (color_space != 7 /* CS_RGB */) {
|
|
// color_range
|
|
bitstream_skip(&bc, 1);
|
|
if (frame->profile == 1 || frame->profile == 3) {
|
|
// subsampling
|
|
bitstream_skip(&bc, 3);
|
|
}
|
|
} else {
|
|
if (frame->profile == 1 || frame->profile == 3)
|
|
bitstream_skip(&bc, 1);
|
|
}
|
|
}
|
|
frame->refresh_frame_flags = bitstream_read(&bc, 8);
|
|
} else {
|
|
frame->refresh_frame_flags = bitstream_read(&bc, 8);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vp9_raw_reorder_make_output(AVBSFContext *bsf,
|
|
AVPacket *out,
|
|
VP9RawReorderFrame *last_frame)
|
|
{
|
|
VP9RawReorderContext *ctx = bsf->priv_data;
|
|
VP9RawReorderFrame *next_output = last_frame,
|
|
*next_display = last_frame, *frame;
|
|
int s, err;
|
|
|
|
for (s = 0; s < FRAME_SLOTS; s++) {
|
|
frame = ctx->slot[s];
|
|
if (!frame)
|
|
continue;
|
|
if (frame->needs_output && (!next_output ||
|
|
frame->sequence < next_output->sequence))
|
|
next_output = frame;
|
|
if (frame->needs_display && (!next_display ||
|
|
frame->pts < next_display->pts))
|
|
next_display = frame;
|
|
}
|
|
|
|
if (!next_output && !next_display)
|
|
return AVERROR_EOF;
|
|
|
|
if (!next_display || (next_output &&
|
|
next_output->sequence < next_display->sequence))
|
|
frame = next_output;
|
|
else
|
|
frame = next_display;
|
|
|
|
if (frame->needs_output && frame->needs_display &&
|
|
next_output == next_display) {
|
|
av_log(bsf, AV_LOG_DEBUG, "Output and display frame "
|
|
"%"PRId64" (%"PRId64") in order.\n",
|
|
frame->sequence, frame->pts);
|
|
|
|
av_packet_move_ref(out, frame->packet);
|
|
|
|
frame->needs_output = frame->needs_display = 0;
|
|
} else if (frame->needs_output) {
|
|
if (frame->needs_display) {
|
|
av_log(bsf, AV_LOG_DEBUG, "Output frame %"PRId64" "
|
|
"(%"PRId64") for later display.\n",
|
|
frame->sequence, frame->pts);
|
|
} else {
|
|
av_log(bsf, AV_LOG_DEBUG, "Output unshown frame "
|
|
"%"PRId64" (%"PRId64") to keep order.\n",
|
|
frame->sequence, frame->pts);
|
|
}
|
|
|
|
av_packet_move_ref(out, frame->packet);
|
|
out->pts = out->dts;
|
|
|
|
frame->needs_output = 0;
|
|
} else {
|
|
PutBitContext pb;
|
|
|
|
av_assert0(!frame->needs_output && frame->needs_display);
|
|
|
|
if (frame->slots == 0) {
|
|
av_log(bsf, AV_LOG_ERROR, "Attempting to display frame "
|
|
"which is no longer available?\n");
|
|
frame->needs_display = 0;
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
s = ff_ctz(frame->slots);
|
|
av_assert0(s < FRAME_SLOTS);
|
|
|
|
av_log(bsf, AV_LOG_DEBUG, "Display frame %"PRId64" "
|
|
"(%"PRId64") from slot %d.\n",
|
|
frame->sequence, frame->pts, s);
|
|
|
|
err = av_new_packet(out, 2);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
init_put_bits(&pb, out->data, 2);
|
|
|
|
// frame_marker
|
|
put_bits(&pb, 2, 2);
|
|
// profile_low_bit
|
|
put_bits(&pb, 1, frame->profile & 1);
|
|
// profile_high_bit
|
|
put_bits(&pb, 1, (frame->profile >> 1) & 1);
|
|
if (frame->profile == 3) {
|
|
// reserved_zero
|
|
put_bits(&pb, 1, 0);
|
|
}
|
|
// show_existing_frame
|
|
put_bits(&pb, 1, 1);
|
|
// frame_to_show_map_idx
|
|
put_bits(&pb, 3, s);
|
|
|
|
while (put_bits_count(&pb) < 16)
|
|
put_bits(&pb, 1, 0);
|
|
|
|
flush_put_bits(&pb);
|
|
out->pts = out->dts = frame->pts;
|
|
|
|
frame->needs_display = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vp9_raw_reorder_filter(AVBSFContext *bsf, AVPacket *out)
|
|
{
|
|
VP9RawReorderContext *ctx = bsf->priv_data;
|
|
VP9RawReorderFrame *frame;
|
|
AVPacket *in;
|
|
int err, s;
|
|
|
|
if (ctx->next_frame) {
|
|
frame = ctx->next_frame;
|
|
|
|
} else {
|
|
err = ff_bsf_get_packet(bsf, &in);
|
|
if (err < 0) {
|
|
if (err == AVERROR_EOF)
|
|
return vp9_raw_reorder_make_output(bsf, out, NULL);
|
|
return err;
|
|
}
|
|
|
|
if (in->data[in->size - 1] & 0xe0 == 0xc0) {
|
|
av_log(bsf, AV_LOG_ERROR, "Input in superframes is not "
|
|
"supported.\n");
|
|
av_packet_free(&in);
|
|
return AVERROR(ENOSYS);
|
|
}
|
|
|
|
frame = av_mallocz(sizeof(*frame));
|
|
if (!frame) {
|
|
av_packet_free(&in);
|
|
return AVERROR(ENOMEM);
|
|
}
|
|
|
|
frame->packet = in;
|
|
frame->pts = in->pts;
|
|
frame->sequence = ++ctx->sequence;
|
|
err = vp9_raw_reorder_frame_parse(bsf, frame);
|
|
if (err) {
|
|
av_log(bsf, AV_LOG_ERROR, "Failed to parse input "
|
|
"frame: %d.\n", err);
|
|
goto fail;
|
|
}
|
|
|
|
frame->needs_output = 1;
|
|
frame->needs_display = frame->pts != AV_NOPTS_VALUE;
|
|
|
|
if (frame->show_existing_frame)
|
|
av_log(bsf, AV_LOG_DEBUG, "Show frame %"PRId64" "
|
|
"(%"PRId64"): show %u.\n", frame->sequence,
|
|
frame->pts, frame->frame_to_show);
|
|
else
|
|
av_log(bsf, AV_LOG_DEBUG, "New frame %"PRId64" "
|
|
"(%"PRId64"): type %u show %u refresh %02x.\n",
|
|
frame->sequence, frame->pts, frame->frame_type,
|
|
frame->show_frame, frame->refresh_frame_flags);
|
|
|
|
ctx->next_frame = frame;
|
|
}
|
|
|
|
for (s = 0; s < FRAME_SLOTS; s++) {
|
|
if (!(frame->refresh_frame_flags & (1 << s)))
|
|
continue;
|
|
if (ctx->slot[s] && ctx->slot[s]->needs_display &&
|
|
ctx->slot[s]->slots == (1 << s)) {
|
|
// We are overwriting this slot, which is last reference
|
|
// to the frame previously present in it. In order to be
|
|
// a valid stream, that frame must already have been
|
|
// displayed before the pts of the current frame.
|
|
err = vp9_raw_reorder_make_output(bsf, out, ctx->slot[s]);
|
|
if (err < 0) {
|
|
av_log(bsf, AV_LOG_ERROR, "Failed to create "
|
|
"output overwriting slot %d: %d.\n",
|
|
s, err);
|
|
// Clear the slot anyway, so we don't end up
|
|
// in an infinite loop.
|
|
vp9_raw_reorder_clear_slot(ctx, s);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
return 0;
|
|
}
|
|
vp9_raw_reorder_clear_slot(ctx, s);
|
|
}
|
|
|
|
for (s = 0; s < FRAME_SLOTS; s++) {
|
|
if (!(frame->refresh_frame_flags & (1 << s)))
|
|
continue;
|
|
ctx->slot[s] = frame;
|
|
}
|
|
frame->slots = frame->refresh_frame_flags;
|
|
|
|
if (!frame->refresh_frame_flags) {
|
|
err = vp9_raw_reorder_make_output(bsf, out, frame);
|
|
if (err < 0) {
|
|
av_log(bsf, AV_LOG_ERROR, "Failed to create output "
|
|
"for transient frame.\n");
|
|
ctx->next_frame = NULL;
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
if (!frame->needs_display) {
|
|
vp9_raw_reorder_frame_free(&frame);
|
|
ctx->next_frame = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ctx->next_frame = NULL;
|
|
return AVERROR(EAGAIN);
|
|
|
|
fail:
|
|
vp9_raw_reorder_frame_free(&frame);
|
|
return err;
|
|
}
|
|
|
|
static void vp9_raw_reorder_close(AVBSFContext *bsf)
|
|
{
|
|
VP9RawReorderContext *ctx = bsf->priv_data;
|
|
int s;
|
|
|
|
for (s = 0; s < FRAME_SLOTS; s++)
|
|
vp9_raw_reorder_clear_slot(ctx, s);
|
|
}
|
|
|
|
static const enum AVCodecID vp9_raw_reorder_codec_ids[] = {
|
|
AV_CODEC_ID_VP9, AV_CODEC_ID_NONE,
|
|
};
|
|
|
|
const AVBitStreamFilter ff_vp9_raw_reorder_bsf = {
|
|
.name = "vp9_raw_reorder",
|
|
.priv_data_size = sizeof(VP9RawReorderContext),
|
|
.close = &vp9_raw_reorder_close,
|
|
.filter = &vp9_raw_reorder_filter,
|
|
.codec_ids = vp9_raw_reorder_codec_ids,
|
|
};
|