/* * This file is part of FFmpeg. * * FFmpeg 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. * * FFmpeg 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 FFmpeg; 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 "bsf_internal.h" #include "get_bits.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) { GetBitContext 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 = init_get_bits(&bc, frame->packet->data, 8 * frame->packet->size); if (err) return err; frame_marker = get_bits(&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 = get_bits1(&bc); profile_high_bit = get_bits1(&bc); frame->profile = (profile_high_bit << 1) | profile_low_bit; if (frame->profile == 3) { reserved_zero = get_bits1(&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 = get_bits1(&bc); if (frame->show_existing_frame) { frame->frame_to_show = get_bits(&bc, 3); return 0; } frame->frame_type = get_bits1(&bc); frame->show_frame = get_bits1(&bc); error_resilient_mode = get_bits1(&bc); if (frame->frame_type == 0) { frame_sync_code = get_bits(&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 = get_bits1(&bc); else intra_only = 0; if (error_resilient_mode == 0) { // reset_frame_context skip_bits(&bc, 2); } if (intra_only) { frame_sync_code = get_bits(&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 skip_bits(&bc, 1); } color_space = get_bits(&bc, 3); if (color_space != 7 /* CS_RGB */) { // color_range skip_bits(&bc, 1); if (frame->profile == 1 || frame->profile == 3) { // subsampling skip_bits(&bc, 3); } } else { if (frame->profile == 1 || frame->profile == 3) skip_bits(&bc, 1); } } frame->refresh_frame_flags = get_bits(&bc, 8); } else { frame->refresh_frame_flags = get_bits(&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_flush(AVBSFContext *bsf) { VP9RawReorderContext *ctx = bsf->priv_data; for (int s = 0; s < FRAME_SLOTS; s++) vp9_raw_reorder_clear_slot(ctx, s); ctx->next_frame = NULL; ctx->sequence = 0; } 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, .flush = &vp9_raw_reorder_flush, .filter = &vp9_raw_reorder_filter, .codec_ids = vp9_raw_reorder_codec_ids, };