mirror of https://github.com/FFmpeg/FFmpeg.git
Partially based on code by Ronald S. Bultje <rsbultje@gmail.com>.pull/254/merge
parent
8fb4210ad8
commit
03a80925ef
4 changed files with 152 additions and 0 deletions
@ -0,0 +1,146 @@ |
||||
/*
|
||||
* 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 |
||||
*/ |
||||
|
||||
/**
|
||||
* @file |
||||
* This bitstream filter splits VP9 superframes into packets containing |
||||
* just one frame. |
||||
*/ |
||||
|
||||
#include <stddef.h> |
||||
|
||||
#include "avcodec.h" |
||||
#include "bsf.h" |
||||
#include "bitstream.h" |
||||
#include "bytestream.h" |
||||
|
||||
typedef struct VP9SFSplitContext { |
||||
AVPacket *buffer_pkt; |
||||
|
||||
int nb_frames; |
||||
int next_frame; |
||||
size_t next_frame_offset; |
||||
int sizes[8]; |
||||
} VP9SFSplitContext; |
||||
|
||||
static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) |
||||
{ |
||||
VP9SFSplitContext *s = ctx->priv_data; |
||||
AVPacket *in; |
||||
int i, j, ret, marker; |
||||
int is_superframe = !!s->buffer_pkt; |
||||
|
||||
if (!s->buffer_pkt) { |
||||
ret = ff_bsf_get_packet(ctx, &s->buffer_pkt); |
||||
if (ret < 0) |
||||
return ret; |
||||
in = s->buffer_pkt; |
||||
|
||||
marker = in->data[in->size - 1]; |
||||
if ((marker & 0xe0) == 0xc0) { |
||||
int length_size = 1 + ((marker >> 3) & 0x3); |
||||
int nb_frames = 1 + (marker & 0x7); |
||||
int idx_size = 2 + nb_frames * length_size; |
||||
|
||||
if (in->size >= idx_size && in->data[in->size - idx_size] == marker) { |
||||
GetByteContext bc; |
||||
int total_size = 0; |
||||
|
||||
bytestream2_init(&bc, in->data + in->size + 1 - idx_size, |
||||
nb_frames * length_size); |
||||
|
||||
for (i = 0; i < nb_frames; i++) { |
||||
int frame_size = 0; |
||||
for (j = 0; j < length_size; j++) |
||||
frame_size |= bytestream2_get_byte(&bc) << (j * 8); |
||||
|
||||
total_size += frame_size; |
||||
if (total_size > in->size - idx_size) { |
||||
av_log(ctx, AV_LOG_ERROR, |
||||
"Invalid frame size in a superframe: %d\n", frame_size); |
||||
ret = AVERROR(EINVAL); |
||||
goto fail; |
||||
} |
||||
s->sizes[i] = frame_size; |
||||
} |
||||
s->nb_frames = nb_frames; |
||||
s->next_frame = 0; |
||||
s->next_frame_offset = 0; |
||||
is_superframe = 1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (is_superframe) { |
||||
BitstreamContext bc; |
||||
int profile, invisible = 0; |
||||
|
||||
ret = av_packet_ref(out, s->buffer_pkt); |
||||
if (ret < 0) |
||||
goto fail; |
||||
|
||||
out->data += s->next_frame_offset; |
||||
out->size = s->sizes[s->next_frame]; |
||||
|
||||
s->next_frame_offset += out->size; |
||||
s->next_frame++; |
||||
|
||||
if (s->next_frame >= s->nb_frames) |
||||
av_packet_free(&s->buffer_pkt); |
||||
|
||||
ret = bitstream_init8(&bc, out->data, out->size); |
||||
if (ret < 0) |
||||
goto fail; |
||||
|
||||
bitstream_read(&bc, 2); // frame_marker
|
||||
profile = bitstream_read(&bc, 1); |
||||
profile |= bitstream_read(&bc, 1) << 1; |
||||
if (profile == 3) |
||||
bitstream_read(&bc, 1); |
||||
if (!bitstream_read(&bc, 1)) { |
||||
bitstream_read(&bc, 1); |
||||
invisible = !bitstream_read(&bc, 1); |
||||
} |
||||
|
||||
if (invisible) |
||||
out->pts = AV_NOPTS_VALUE; |
||||
|
||||
} else { |
||||
av_packet_move_ref(out, s->buffer_pkt); |
||||
av_packet_free(&s->buffer_pkt); |
||||
} |
||||
|
||||
return 0; |
||||
fail: |
||||
av_packet_free(&s->buffer_pkt); |
||||
return ret; |
||||
} |
||||
|
||||
static void vp9_superframe_split_uninit(AVBSFContext *ctx) |
||||
{ |
||||
VP9SFSplitContext *s = ctx->priv_data; |
||||
av_packet_free(&s->buffer_pkt); |
||||
} |
||||
|
||||
const AVBitStreamFilter ff_vp9_superframe_split_bsf = { |
||||
.name = "vp9_superframe_split", |
||||
.priv_data_size = sizeof(VP9SFSplitContext), |
||||
.close = vp9_superframe_split_uninit, |
||||
.filter = vp9_superframe_split_filter, |
||||
.codec_ids = (const enum AVCodecID []){ AV_CODEC_ID_VP9, AV_CODEC_ID_NONE }, |
||||
}; |
Loading…
Reference in new issue