Bug 1745285 Build AV1 decoding support in ffvpx r=alwu

Enable DAV1D decoder in bundled ffvpx and build ffvpx with bundled DAV1D decoder.

Differential Revision: https://phabricator.services.mozilla.com/D135034
This commit is contained in:
stransky 2022-01-11 18:42:27 +00:00
Родитель 4354b92057
Коммит 03ec7b6a39
21 изменённых файлов: 930 добавлений и 7 удалений

Просмотреть файл

@ -474,13 +474,14 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER>::DoDecode(
res = mLib->avcodec_receive_frame(mCodecContext, mFrame);
if (res == int(AVERROR_EOF)) {
FFMPEG_LOG(" End of stream.");
return NS_ERROR_DOM_MEDIA_END_OF_STREAM;
}
if (res == AVERROR(EAGAIN)) {
return NS_OK;
}
if (res < 0) {
FFMPEG_LOG("avcodec_receive_frame error: %d", res);
FFMPEG_LOG(" avcodec_receive_frame error: %d", res);
return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
RESULT_DETAIL("avcodec_receive_frame error: %d", res));
}
@ -594,6 +595,8 @@ gfx::YUVColorSpace FFmpegVideoDecoder<LIBAV_VER>::GetFrameColorSpace() const {
case AVCOL_SPC_SMPTE170M:
case AVCOL_SPC_BT470BG:
return gfx::YUVColorSpace::BT601;
case AVCOL_SPC_RGB:
return gfx::YUVColorSpace::Identity;
default:
break;
}
@ -627,6 +630,9 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER>::CreateImage(
mCodecContext->pix_fmt == AV_PIX_FMT_YUV444P10LE
#if LIBAVCODEC_VERSION_MAJOR >= 57
|| mCodecContext->pix_fmt == AV_PIX_FMT_YUV444P12LE
#endif
#if defined(MOZ_AV1) && defined(FFVPX_VERSION)
|| mCodecContext->pix_fmt == AV_PIX_FMT_GBRP
#endif
) {
b.mPlanes[1].mWidth = b.mPlanes[2].mWidth = mFrame->width;

Просмотреть файл

@ -658,7 +658,9 @@
%define CONFIG_VP9_SUPERFRAME_SPLIT_BSF 1
%define CONFIG_VP8_DECODER 1
%define CONFIG_VP9_DECODER 1
%define CONFIG_AV1_DECODER 0
%define CONFIG_FLAC_DECODER 1
%define CONFIG_MP3_DECODER 1
%define CONFIG_VP8_PARSER 1
%define CONFIG_VP9_PARSER 1
%define CONFIG_AV1_PARSER 0

Просмотреть файл

@ -673,8 +673,10 @@
#define CONFIG_VP9_SUPERFRAME_SPLIT_BSF 1
#define CONFIG_VP8_DECODER 1
#define CONFIG_VP9_DECODER 1
#define CONFIG_AV1_DECODER 0
#define CONFIG_FLAC_DECODER 1
#define CONFIG_MP3_DECODER 1
#define CONFIG_VP8_PARSER 1
#define CONFIG_VP9_PARSER 1
#define CONFIG_AV1_PARSER 0
#endif /* FFMPEG_CONFIG_H */

Просмотреть файл

@ -438,7 +438,7 @@
#define CONFIG_LIBCACA 0
#define CONFIG_LIBCELT 0
#define CONFIG_LIBCODEC2 0
#define CONFIG_LIBDAV1D 0
#define CONFIG_LIBDAV1D 1
#define CONFIG_LIBDC1394 0
#define CONFIG_LIBDRM 0
#define CONFIG_LIBFLITE 0

Просмотреть файл

@ -424,7 +424,7 @@
%define CONFIG_LIBCACA 0
%define CONFIG_LIBCELT 0
%define CONFIG_LIBCODEC2 0
%define CONFIG_LIBDAV1D 0
%define CONFIG_LIBDAV1D 1
%define CONFIG_LIBDC1394 0
%define CONFIG_LIBDRM 0
%define CONFIG_LIBFLITE 0

Просмотреть файл

@ -658,7 +658,9 @@
%define CONFIG_VP9_SUPERFRAME_SPLIT_BSF 1
%define CONFIG_VP8_DECODER 1
%define CONFIG_VP9_DECODER 1
%define CONFIG_AV1_DECODER 0
%define CONFIG_FLAC_DECODER 1
%define CONFIG_MP3_DECODER 1
%define CONFIG_VP8_PARSER 1
%define CONFIG_VP9_PARSER 1
%define CONFIG_AV1_PARSER 0

Просмотреть файл

@ -673,8 +673,10 @@
#define CONFIG_VP9_SUPERFRAME_SPLIT_BSF 1
#define CONFIG_VP8_DECODER 1
#define CONFIG_VP9_DECODER 1
#define CONFIG_AV1_DECODER 0
#define CONFIG_FLAC_DECODER 1
#define CONFIG_MP3_DECODER 1
#define CONFIG_VP8_PARSER 1
#define CONFIG_VP9_PARSER 1
#define CONFIG_AV1_PARSER 0
#endif /* FFMPEG_CONFIG_H */

Просмотреть файл

@ -658,7 +658,9 @@
%define CONFIG_VP9_SUPERFRAME_SPLIT_BSF 1
%define CONFIG_VP8_DECODER 1
%define CONFIG_VP9_DECODER 1
%define CONFIG_AV1_DECODER 0
%define CONFIG_FLAC_DECODER 1
%define CONFIG_MP3_DECODER 1
%define CONFIG_VP8_PARSER 1
%define CONFIG_VP9_PARSER 1
%define CONFIG_VP9_PARSER 1
%define CONFIG_AV1_PARSER 0

Просмотреть файл

@ -673,8 +673,10 @@
#define CONFIG_VP9_SUPERFRAME_SPLIT_BSF 1
#define CONFIG_VP8_DECODER 1
#define CONFIG_VP9_DECODER 1
#define CONFIG_AV1_DECODER 0
#define CONFIG_FLAC_DECODER 1
#define CONFIG_MP3_DECODER 1
#define CONFIG_VP8_PARSER 1
#define CONFIG_VP9_PARSER 1
#define CONFIG_AV1_PARSER 0
#endif /* FFMPEG_CONFIG_H */

Просмотреть файл

@ -229,7 +229,6 @@
%define CONFIG_AURA_DECODER 0
%define CONFIG_AV1_FRAME_SPLIT_BSF 0
%define CONFIG_AV1_METADATA_BSF 0
%define CONFIG_AV1_PARSER 0
%define CONFIG_AV1_D3D11VA_HWACCEL 0
%define CONFIG_AV1_D3D11VA2_HWACCEL 0
%define CONFIG_AV1_DXVA2_HWACCEL 0

Просмотреть файл

@ -229,8 +229,6 @@
#define CONFIG_AURA_DECODER 0
#define CONFIG_AV1_FRAME_SPLIT_BSF 0
#define CONFIG_AV1_METADATA_BSF 0
#define CONFIG_AV1_PARSER 0
#define CONFIG_AV1_DECODER 0
#define CONFIG_AV1_D3D11VA_HWACCEL 0
#define CONFIG_AV1_D3D11VA2_HWACCEL 0
#define CONFIG_AV1_DXVA2_HWACCEL 0

Просмотреть файл

@ -0,0 +1,119 @@
/*
* 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 <stddef.h>
#include <stdint.h>
#include "atsc_a53.h"
#include "get_bits.h"
int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len,
void **data, size_t *sei_size)
{
AVFrameSideData *side_data = NULL;
uint8_t *sei_data;
if (frame)
side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC);
if (!side_data) {
*data = NULL;
return 0;
}
*sei_size = side_data->size + 11;
*data = av_mallocz(*sei_size + prefix_len);
if (!*data)
return AVERROR(ENOMEM);
sei_data = (uint8_t*)*data + prefix_len;
// country code
sei_data[0] = 181;
sei_data[1] = 0;
sei_data[2] = 49;
/**
* 'GA94' is standard in North America for ATSC, but hard coding
* this style may not be the right thing to do -- other formats
* do exist. This information is not available in the side_data
* so we are going with this right now.
*/
AV_WL32(sei_data + 3, MKTAG('G', 'A', '9', '4'));
sei_data[7] = 3;
sei_data[8] = ((side_data->size/3) & 0x1f) | 0x40;
sei_data[9] = 0;
memcpy(sei_data + 10, side_data->data, side_data->size);
sei_data[side_data->size+10] = 255;
return 0;
}
int ff_parse_a53_cc(AVBufferRef **pbuf, const uint8_t *data, int size)
{
AVBufferRef *buf = *pbuf;
GetBitContext gb;
size_t new_size, old_size = buf ? buf->size : 0;
int ret, cc_count;
if (size < 3)
return AVERROR(EINVAL);
ret = init_get_bits8(&gb, data, size);
if (ret < 0)
return ret;
if (get_bits(&gb, 8) != 0x3) // user_data_type_code
return 0;
skip_bits(&gb, 1); // reserved
if (!get_bits(&gb, 1)) // process_cc_data_flag
return 0;
skip_bits(&gb, 1); // zero bit
cc_count = get_bits(&gb, 5);
if (!cc_count)
return 0;
skip_bits(&gb, 8); // reserved
/* 3 bytes per CC plus one byte marker_bits at the end */
if (cc_count * 3 >= (get_bits_left(&gb) >> 3))
return AVERROR(EINVAL);
new_size = (old_size + cc_count * 3);
if (new_size > INT_MAX)
return AVERROR(EINVAL);
/* Allow merging of the cc data from two fields. */
ret = av_buffer_realloc(pbuf, new_size);
if (ret < 0)
return ret;
buf = *pbuf;
/* Use of av_buffer_realloc assumes buffer is writeable */
for (int i = 0; i < cc_count; i++) {
buf->data[old_size++] = get_bits(&gb, 8);
buf->data[old_size++] = get_bits(&gb, 8);
buf->data[old_size++] = get_bits(&gb, 8);
}
return cc_count;
}

Просмотреть файл

@ -0,0 +1,56 @@
/*
* 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
*/
#ifndef AVCODEC_ATSC_A53_H
#define AVCODEC_ATSC_A53_H
#include <stddef.h>
#include <stdint.h>
#include "libavutil/buffer.h"
#include "libavutil/frame.h"
/**
* Check AVFrame for A53 side data and allocate and fill SEI message with A53 info
*
* @param frame Raw frame to get A53 side data from
* @param prefix_len Number of bytes to allocate before SEI message
* @param data Pointer to a variable to store allocated memory
* Upon return the variable will hold NULL on error or if frame has no A53 info.
* Otherwise it will point to prefix_len uninitialized bytes followed by
* *sei_size SEI message
* @param sei_size Pointer to a variable to store generated SEI message length
* @return Zero on success, negative error code on failure
*/
int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len,
void **data, size_t *sei_size);
/**
* Parse a data array for ATSC A53 Part 4 Closed Captions and store them in an AVBufferRef.
*
* @param pbuf Pointer to an AVBufferRef to append the closed captions. *pbuf may be NULL, in
* which case a new buffer will be allocated and put in it.
* @param data The data array containing the raw A53 data.
* @param size Size of the data array in bytes.
*
* @return Number of closed captions parsed on success, negative error code on failure.
* If no Closed Captions are parsed, *pbuf is untouched.
*/
int ff_parse_a53_cc(AVBufferRef **pbuf, const uint8_t *data, int size);
#endif /* AVCODEC_ATSC_A53_H */

Просмотреть файл

@ -8,6 +8,7 @@ av_codec_get_pkt_timebase
av_codec_get_seek_preroll
av_codec_is_decoder
av_codec_is_encoder
av_codec_iterate
av_codec_next
av_codec_set_chroma_intra_matrix
av_codec_set_codec_descriptor

Просмотреть файл

@ -11,6 +11,9 @@ static const AVCodec * const codec_list[] = {
#if CONFIG_MP3_DECODER
&ff_mp3_decoder,
#endif
#if CONFIG_LIBDAV1D
&ff_libdav1d_decoder,
#endif
#if CONFIG_AV1_DECODER
&ff_av1_decoder,
#endif

Просмотреть файл

@ -0,0 +1,512 @@
/*
* Copyright (c) 2018 Ronald S. Bultje <rsbultje gmail com>
* Copyright (c) 2018 James Almer <jamrial gmail com>
*
* 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 "dav1d/dav1d.h"
#include "libavutil/avassert.h"
#include "libavutil/film_grain_params.h"
#include "libavutil/mastering_display_metadata.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "atsc_a53.h"
#include "avcodec.h"
#include "bytestream.h"
#include "decode.h"
#include "internal.h"
#define FF_DAV1D_VERSION_AT_LEAST(x,y) \
(DAV1D_API_VERSION_MAJOR > (x) || DAV1D_API_VERSION_MAJOR == (x) && DAV1D_API_VERSION_MINOR >= (y))
typedef struct Libdav1dContext {
AVClass *class;
Dav1dContext *c;
AVBufferPool *pool;
int pool_size;
Dav1dData data;
int tile_threads;
int frame_threads;
int apply_grain;
int operating_point;
int all_layers;
} Libdav1dContext;
static const enum AVPixelFormat pix_fmt[][3] = {
[DAV1D_PIXEL_LAYOUT_I400] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12 },
[DAV1D_PIXEL_LAYOUT_I420] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P12 },
[DAV1D_PIXEL_LAYOUT_I422] = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12 },
[DAV1D_PIXEL_LAYOUT_I444] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12 },
};
static const enum AVPixelFormat pix_fmt_rgb[3] = {
AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
};
static void libdav1d_log_callback(void *opaque, const char *fmt, va_list vl)
{
AVCodecContext *c = opaque;
av_vlog(c, AV_LOG_ERROR, fmt, vl);
}
static int libdav1d_picture_allocator(Dav1dPicture *p, void *cookie)
{
Libdav1dContext *dav1d = cookie;
enum AVPixelFormat format = pix_fmt[p->p.layout][p->seq_hdr->hbd];
int ret, linesize[4], h = FFALIGN(p->p.h, 128), w = FFALIGN(p->p.w, 128);
uint8_t *aligned_ptr, *data[4];
AVBufferRef *buf;
ret = av_image_get_buffer_size(format, w, h, DAV1D_PICTURE_ALIGNMENT);
if (ret < 0)
return ret;
if (ret != dav1d->pool_size) {
av_buffer_pool_uninit(&dav1d->pool);
// Use twice the amount of required padding bytes for aligned_ptr below.
dav1d->pool = av_buffer_pool_init(ret + DAV1D_PICTURE_ALIGNMENT * 2, NULL);
if (!dav1d->pool) {
dav1d->pool_size = 0;
return AVERROR(ENOMEM);
}
dav1d->pool_size = ret;
}
buf = av_buffer_pool_get(dav1d->pool);
if (!buf)
return AVERROR(ENOMEM);
// libdav1d requires DAV1D_PICTURE_ALIGNMENT aligned buffers, which av_malloc()
// doesn't guarantee for example when AVX is disabled at configure time.
// Use the extra DAV1D_PICTURE_ALIGNMENT padding bytes in the buffer to align it
// if required.
aligned_ptr = (uint8_t *)FFALIGN((uintptr_t)buf->data, DAV1D_PICTURE_ALIGNMENT);
ret = av_image_fill_arrays(data, linesize, aligned_ptr, format, w, h,
DAV1D_PICTURE_ALIGNMENT);
if (ret < 0) {
av_buffer_unref(&buf);
return ret;
}
p->data[0] = data[0];
p->data[1] = data[1];
p->data[2] = data[2];
p->stride[0] = linesize[0];
p->stride[1] = linesize[1];
p->allocator_data = buf;
return 0;
}
static void libdav1d_picture_release(Dav1dPicture *p, void *cookie)
{
AVBufferRef *buf = p->allocator_data;
av_buffer_unref(&buf);
}
static av_cold int libdav1d_init(AVCodecContext *c)
{
Libdav1dContext *dav1d = c->priv_data;
Dav1dSettings s;
int threads = (c->thread_count ? c->thread_count : av_cpu_count()) * 3 / 2;
int res;
av_log(c, AV_LOG_INFO, "libdav1d %s\n", dav1d_version());
dav1d_default_settings(&s);
s.logger.cookie = c;
s.logger.callback = libdav1d_log_callback;
s.allocator.cookie = dav1d;
s.allocator.alloc_picture_callback = libdav1d_picture_allocator;
s.allocator.release_picture_callback = libdav1d_picture_release;
s.frame_size_limit = c->max_pixels;
if (dav1d->apply_grain >= 0)
s.apply_grain = dav1d->apply_grain;
else if (c->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)
s.apply_grain = 0;
s.all_layers = dav1d->all_layers;
if (dav1d->operating_point >= 0)
s.operating_point = dav1d->operating_point;
#if FF_DAV1D_VERSION_AT_LEAST(6,0)
if (dav1d->frame_threads || dav1d->tile_threads)
s.n_threads = FFMAX(dav1d->frame_threads, dav1d->tile_threads);
else
s.n_threads = FFMIN(threads, DAV1D_MAX_THREADS);
s.max_frame_delay = (c->flags & AV_CODEC_FLAG_LOW_DELAY) ? 1 : s.n_threads;
av_log(c, AV_LOG_DEBUG, "Using %d threads, %d max_frame_delay\n",
s.n_threads, s.max_frame_delay);
#else
s.n_tile_threads = dav1d->tile_threads
? dav1d->tile_threads
: FFMIN(floor(sqrt(threads)), DAV1D_MAX_TILE_THREADS);
s.n_frame_threads = dav1d->frame_threads
? dav1d->frame_threads
: FFMIN(ceil(threads / s.n_tile_threads), DAV1D_MAX_FRAME_THREADS);
av_log(c, AV_LOG_DEBUG, "Using %d frame threads, %d tile threads\n",
s.n_frame_threads, s.n_tile_threads);
#endif
res = dav1d_open(&dav1d->c, &s);
if (res < 0)
return AVERROR(ENOMEM);
return 0;
}
static void libdav1d_flush(AVCodecContext *c)
{
Libdav1dContext *dav1d = c->priv_data;
dav1d_data_unref(&dav1d->data);
dav1d_flush(dav1d->c);
}
static void libdav1d_data_free(const uint8_t *data, void *opaque) {
AVBufferRef *buf = opaque;
av_buffer_unref(&buf);
}
static void libdav1d_user_data_free(const uint8_t *data, void *opaque) {
av_assert0(data == opaque);
av_free(opaque);
}
static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame)
{
Libdav1dContext *dav1d = c->priv_data;
Dav1dData *data = &dav1d->data;
Dav1dPicture pic = { 0 }, *p = &pic;
int res;
if (!data->sz) {
AVPacket pkt = { 0 };
res = ff_decode_get_packet(c, &pkt);
if (res < 0 && res != AVERROR_EOF)
return res;
if (pkt.size) {
res = dav1d_data_wrap(data, pkt.data, pkt.size, libdav1d_data_free, pkt.buf);
if (res < 0) {
av_packet_unref(&pkt);
return res;
}
data->m.timestamp = pkt.pts;
data->m.offset = pkt.pos;
data->m.duration = pkt.duration;
pkt.buf = NULL;
av_packet_unref(&pkt);
if (c->reordered_opaque != AV_NOPTS_VALUE) {
uint8_t *reordered_opaque = av_malloc(sizeof(c->reordered_opaque));
if (!reordered_opaque) {
dav1d_data_unref(data);
return AVERROR(ENOMEM);
}
memcpy(reordered_opaque, &c->reordered_opaque, sizeof(c->reordered_opaque));
res = dav1d_data_wrap_user_data(data, reordered_opaque,
libdav1d_user_data_free, reordered_opaque);
if (res < 0) {
av_free(reordered_opaque);
dav1d_data_unref(data);
return res;
}
}
}
}
res = dav1d_send_data(dav1d->c, data);
if (res < 0) {
if (res == AVERROR(EINVAL))
res = AVERROR_INVALIDDATA;
if (res != AVERROR(EAGAIN))
return res;
}
res = dav1d_get_picture(dav1d->c, p);
if (res < 0) {
if (res == AVERROR(EINVAL))
res = AVERROR_INVALIDDATA;
else if (res == AVERROR(EAGAIN) && c->internal->draining)
res = AVERROR_EOF;
return res;
}
av_assert0(p->data[0] && p->allocator_data);
// This requires the custom allocator above
frame->buf[0] = av_buffer_ref(p->allocator_data);
if (!frame->buf[0]) {
dav1d_picture_unref(p);
return AVERROR(ENOMEM);
}
frame->data[0] = p->data[0];
frame->data[1] = p->data[1];
frame->data[2] = p->data[2];
frame->linesize[0] = p->stride[0];
frame->linesize[1] = p->stride[1];
frame->linesize[2] = p->stride[1];
c->profile = p->seq_hdr->profile;
c->level = ((p->seq_hdr->operating_points[0].major_level - 2) << 2)
| p->seq_hdr->operating_points[0].minor_level;
frame->width = p->p.w;
frame->height = p->p.h;
if (c->width != p->p.w || c->height != p->p.h) {
res = ff_set_dimensions(c, p->p.w, p->p.h);
if (res < 0)
goto fail;
}
av_reduce(&frame->sample_aspect_ratio.num,
&frame->sample_aspect_ratio.den,
frame->height * (int64_t)p->frame_hdr->render_width,
frame->width * (int64_t)p->frame_hdr->render_height,
INT_MAX);
ff_set_sar(c, frame->sample_aspect_ratio);
switch (p->seq_hdr->chr) {
case DAV1D_CHR_VERTICAL:
frame->chroma_location = c->chroma_sample_location = AVCHROMA_LOC_LEFT;
break;
case DAV1D_CHR_COLOCATED:
frame->chroma_location = c->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
break;
}
frame->colorspace = c->colorspace = (enum AVColorSpace) p->seq_hdr->mtrx;
frame->color_primaries = c->color_primaries = (enum AVColorPrimaries) p->seq_hdr->pri;
frame->color_trc = c->color_trc = (enum AVColorTransferCharacteristic) p->seq_hdr->trc;
frame->color_range = c->color_range = p->seq_hdr->color_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
if (p->p.layout == DAV1D_PIXEL_LAYOUT_I444 &&
p->seq_hdr->mtrx == DAV1D_MC_IDENTITY &&
p->seq_hdr->pri == DAV1D_COLOR_PRI_BT709 &&
p->seq_hdr->trc == DAV1D_TRC_SRGB)
frame->format = c->pix_fmt = pix_fmt_rgb[p->seq_hdr->hbd];
else
frame->format = c->pix_fmt = pix_fmt[p->p.layout][p->seq_hdr->hbd];
if (p->m.user_data.data)
memcpy(&frame->reordered_opaque, p->m.user_data.data, sizeof(frame->reordered_opaque));
else
frame->reordered_opaque = AV_NOPTS_VALUE;
if (p->seq_hdr->num_units_in_tick && p->seq_hdr->time_scale) {
av_reduce(&c->framerate.den, &c->framerate.num,
p->seq_hdr->num_units_in_tick, p->seq_hdr->time_scale, INT_MAX);
if (p->seq_hdr->equal_picture_interval)
c->ticks_per_frame = p->seq_hdr->num_ticks_per_picture;
}
// match timestamps and packet size
frame->pts = p->m.timestamp;
#if FF_API_PKT_PTS
FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = p->m.timestamp;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
frame->pkt_dts = p->m.timestamp;
frame->pkt_pos = p->m.offset;
frame->pkt_size = p->m.size;
frame->pkt_duration = p->m.duration;
frame->key_frame = p->frame_hdr->frame_type == DAV1D_FRAME_TYPE_KEY;
switch (p->frame_hdr->frame_type) {
case DAV1D_FRAME_TYPE_KEY:
case DAV1D_FRAME_TYPE_INTRA:
frame->pict_type = AV_PICTURE_TYPE_I;
break;
case DAV1D_FRAME_TYPE_INTER:
frame->pict_type = AV_PICTURE_TYPE_P;
break;
case DAV1D_FRAME_TYPE_SWITCH:
frame->pict_type = AV_PICTURE_TYPE_SP;
break;
default:
res = AVERROR_INVALIDDATA;
goto fail;
}
if (p->mastering_display) {
AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame);
if (!mastering) {
res = AVERROR(ENOMEM);
goto fail;
}
for (int i = 0; i < 3; i++) {
mastering->display_primaries[i][0] = av_make_q(p->mastering_display->primaries[i][0], 1 << 16);
mastering->display_primaries[i][1] = av_make_q(p->mastering_display->primaries[i][1], 1 << 16);
}
mastering->white_point[0] = av_make_q(p->mastering_display->white_point[0], 1 << 16);
mastering->white_point[1] = av_make_q(p->mastering_display->white_point[1], 1 << 16);
mastering->max_luminance = av_make_q(p->mastering_display->max_luminance, 1 << 8);
mastering->min_luminance = av_make_q(p->mastering_display->min_luminance, 1 << 14);
mastering->has_primaries = 1;
mastering->has_luminance = 1;
}
if (p->content_light) {
AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame);
if (!light) {
res = AVERROR(ENOMEM);
goto fail;
}
light->MaxCLL = p->content_light->max_content_light_level;
light->MaxFALL = p->content_light->max_frame_average_light_level;
}
if (p->itut_t35) {
GetByteContext gb;
unsigned int user_identifier;
bytestream2_init(&gb, p->itut_t35->payload, p->itut_t35->payload_size);
bytestream2_skip(&gb, 1); // terminal provider code
bytestream2_skip(&gb, 1); // terminal provider oriented code
user_identifier = bytestream2_get_be32(&gb);
switch (user_identifier) {
case MKBETAG('G', 'A', '9', '4'): { // closed captions
AVBufferRef *buf = NULL;
res = ff_parse_a53_cc(&buf, gb.buffer, bytestream2_get_bytes_left(&gb));
if (res < 0)
goto fail;
if (!res)
break;
if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_A53_CC, buf))
av_buffer_unref(&buf);
c->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
break;
}
default: // ignore unsupported identifiers
break;
}
}
if (p->frame_hdr->film_grain.present && (!dav1d->apply_grain ||
(c->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN))) {
AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(frame);
if (!fgp) {
res = AVERROR(ENOMEM);
goto fail;
}
fgp->type = AV_FILM_GRAIN_PARAMS_AV1;
fgp->seed = p->frame_hdr->film_grain.data.seed;
fgp->codec.aom.num_y_points = p->frame_hdr->film_grain.data.num_y_points;
fgp->codec.aom.chroma_scaling_from_luma = p->frame_hdr->film_grain.data.chroma_scaling_from_luma;
fgp->codec.aom.scaling_shift = p->frame_hdr->film_grain.data.scaling_shift;
fgp->codec.aom.ar_coeff_lag = p->frame_hdr->film_grain.data.ar_coeff_lag;
fgp->codec.aom.ar_coeff_shift = p->frame_hdr->film_grain.data.ar_coeff_shift;
fgp->codec.aom.grain_scale_shift = p->frame_hdr->film_grain.data.grain_scale_shift;
fgp->codec.aom.overlap_flag = p->frame_hdr->film_grain.data.overlap_flag;
fgp->codec.aom.limit_output_range = p->frame_hdr->film_grain.data.clip_to_restricted_range;
memcpy(&fgp->codec.aom.y_points, &p->frame_hdr->film_grain.data.y_points,
sizeof(fgp->codec.aom.y_points));
memcpy(&fgp->codec.aom.num_uv_points, &p->frame_hdr->film_grain.data.num_uv_points,
sizeof(fgp->codec.aom.num_uv_points));
memcpy(&fgp->codec.aom.uv_points, &p->frame_hdr->film_grain.data.uv_points,
sizeof(fgp->codec.aom.uv_points));
memcpy(&fgp->codec.aom.ar_coeffs_y, &p->frame_hdr->film_grain.data.ar_coeffs_y,
sizeof(fgp->codec.aom.ar_coeffs_y));
memcpy(&fgp->codec.aom.ar_coeffs_uv[0], &p->frame_hdr->film_grain.data.ar_coeffs_uv[0],
sizeof(fgp->codec.aom.ar_coeffs_uv[0]));
memcpy(&fgp->codec.aom.ar_coeffs_uv[1], &p->frame_hdr->film_grain.data.ar_coeffs_uv[1],
sizeof(fgp->codec.aom.ar_coeffs_uv[1]));
memcpy(&fgp->codec.aom.uv_mult, &p->frame_hdr->film_grain.data.uv_mult,
sizeof(fgp->codec.aom.uv_mult));
memcpy(&fgp->codec.aom.uv_mult_luma, &p->frame_hdr->film_grain.data.uv_luma_mult,
sizeof(fgp->codec.aom.uv_mult_luma));
memcpy(&fgp->codec.aom.uv_offset, &p->frame_hdr->film_grain.data.uv_offset,
sizeof(fgp->codec.aom.uv_offset));
}
res = 0;
fail:
dav1d_picture_unref(p);
if (res < 0)
av_frame_unref(frame);
return res;
}
static av_cold int libdav1d_close(AVCodecContext *c)
{
Libdav1dContext *dav1d = c->priv_data;
av_buffer_pool_uninit(&dav1d->pool);
dav1d_data_unref(&dav1d->data);
dav1d_close(&dav1d->c);
return 0;
}
#ifndef DAV1D_MAX_FRAME_THREADS
#define DAV1D_MAX_FRAME_THREADS DAV1D_MAX_THREADS
#endif
#ifndef DAV1D_MAX_TILE_THREADS
#define DAV1D_MAX_TILE_THREADS DAV1D_MAX_THREADS
#endif
#define OFFSET(x) offsetof(Libdav1dContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption libdav1d_options[] = {
{ "tilethreads", "Tile threads", OFFSET(tile_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_TILE_THREADS, VD },
{ "framethreads", "Frame threads", OFFSET(frame_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_FRAME_THREADS, VD },
{ "filmgrain", "Apply Film Grain", OFFSET(apply_grain), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD | AV_OPT_FLAG_DEPRECATED },
{ "oppoint", "Select an operating point of the scalable bitstream", OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 31, VD },
{ "alllayers", "Output all spatial layers", OFFSET(all_layers), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD },
{ NULL }
};
static const AVClass libdav1d_class = {
.class_name = "libdav1d decoder",
.item_name = av_default_item_name,
.option = libdav1d_options,
.version = LIBAVUTIL_VERSION_INT,
};
AVCodec ff_libdav1d_decoder = {
.name = "libdav1d",
.long_name = NULL_IF_CONFIG_SMALL("dav1d AV1 decoder by VideoLAN"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_AV1,
.priv_data_size = sizeof(Libdav1dContext),
.init = libdav1d_init,
.close = libdav1d_close,
.flush = libdav1d_flush,
.receive_frame = libdav1d_receive_frame,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_SETS_PKT_DTS |
FF_CODEC_CAP_AUTO_THREADS,
.priv_class = &libdav1d_class,
.wrapper_name = "libdav1d",
};

Просмотреть файл

@ -110,6 +110,16 @@ if not CONFIG['MOZ_FFVPX_AUDIOONLY']:
'vaapi_vp9.c',
]
USE_LIBS += ['mozva']
if CONFIG["MOZ_AV1"]:
SOURCES += [
'atsc_a53.c',
'libdav1d.c',
]
USE_LIBS += ['dav1d']
if CONFIG["MOZ_DAV1D_ASM"]:
USE_LIBS += [
'media_libdav1d_asm'
]
if CONFIG['MOZ_LIBAV_FFT']:
SOURCES += [

Просмотреть файл

@ -38,6 +38,9 @@ av_color_space_name
av_color_transfer_name
av_compare_mod
av_compare_ts
#ifdef MOZ_AV1
av_content_light_metadata_create_side_data
#endif
av_cpu_count
av_crc
av_crc_get_table
@ -112,6 +115,9 @@ av_frame_is_writable
av_frame_make_writable
av_frame_move_ref
av_frame_new_side_data
#ifdef MOZ_AV1
av_frame_new_side_data_from_buf
#endif
av_frame_ref
av_frame_remove_side_data
av_frame_set_best_effort_timestamp
@ -195,6 +201,9 @@ av_log_set_flags
av_log_set_level
av_malloc
av_mallocz
#ifdef MOZ_AV1
av_mastering_display_metadata_create_side_data
#endif
av_match_list
av_match_name
av_max_alloc

Просмотреть файл

@ -0,0 +1,66 @@
/**
* Copyright (c) 2016 Neil Birkbeck <neil.birkbeck@gmail.com>
*
* 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 <stdint.h>
#include <string.h>
#include "mastering_display_metadata.h"
#include "mem.h"
AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void)
{
return av_mallocz(sizeof(AVMasteringDisplayMetadata));
}
AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame)
{
AVFrameSideData *side_data = av_frame_new_side_data(frame,
AV_FRAME_DATA_MASTERING_DISPLAY_METADATA,
sizeof(AVMasteringDisplayMetadata));
if (!side_data)
return NULL;
memset(side_data->data, 0, sizeof(AVMasteringDisplayMetadata));
return (AVMasteringDisplayMetadata *)side_data->data;
}
AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size)
{
AVContentLightMetadata *metadata = av_mallocz(sizeof(AVContentLightMetadata));
if (size)
*size = sizeof(*metadata);
return metadata;
}
AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *frame)
{
AVFrameSideData *side_data = av_frame_new_side_data(frame,
AV_FRAME_DATA_CONTENT_LIGHT_LEVEL,
sizeof(AVContentLightMetadata));
if (!side_data)
return NULL;
memset(side_data->data, 0, sizeof(AVContentLightMetadata));
return (AVContentLightMetadata *)side_data->data;
}

Просмотреть файл

@ -0,0 +1,128 @@
/*
* Copyright (c) 2016 Neil Birkbeck <neil.birkbeck@gmail.com>
*
* 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
*/
#ifndef AVUTIL_MASTERING_DISPLAY_METADATA_H
#define AVUTIL_MASTERING_DISPLAY_METADATA_H
#include "frame.h"
#include "rational.h"
/**
* Mastering display metadata capable of representing the color volume of
* the display used to master the content (SMPTE 2086:2014).
*
* To be used as payload of a AVFrameSideData or AVPacketSideData with the
* appropriate type.
*
* @note The struct should be allocated with av_mastering_display_metadata_alloc()
* and its size is not a part of the public ABI.
*/
typedef struct AVMasteringDisplayMetadata {
/**
* CIE 1931 xy chromaticity coords of color primaries (r, g, b order).
*/
AVRational display_primaries[3][2];
/**
* CIE 1931 xy chromaticity coords of white point.
*/
AVRational white_point[2];
/**
* Min luminance of mastering display (cd/m^2).
*/
AVRational min_luminance;
/**
* Max luminance of mastering display (cd/m^2).
*/
AVRational max_luminance;
/**
* Flag indicating whether the display primaries (and white point) are set.
*/
int has_primaries;
/**
* Flag indicating whether the luminance (min_ and max_) have been set.
*/
int has_luminance;
} AVMasteringDisplayMetadata;
/**
* Allocate an AVMasteringDisplayMetadata structure and set its fields to
* default values. The resulting struct can be freed using av_freep().
*
* @return An AVMasteringDisplayMetadata filled with default values or NULL
* on failure.
*/
AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void);
/**
* Allocate a complete AVMasteringDisplayMetadata and add it to the frame.
*
* @param frame The frame which side data is added to.
*
* @return The AVMasteringDisplayMetadata structure to be filled by caller.
*/
AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame);
/**
* Content light level needed by to transmit HDR over HDMI (CTA-861.3).
*
* To be used as payload of a AVFrameSideData or AVPacketSideData with the
* appropriate type.
*
* @note The struct should be allocated with av_content_light_metadata_alloc()
* and its size is not a part of the public ABI.
*/
typedef struct AVContentLightMetadata {
/**
* Max content light level (cd/m^2).
*/
unsigned MaxCLL;
/**
* Max average light level per frame (cd/m^2).
*/
unsigned MaxFALL;
} AVContentLightMetadata;
/**
* Allocate an AVContentLightMetadata structure and set its fields to
* default values. The resulting struct can be freed using av_freep().
*
* @return An AVContentLightMetadata filled with default values or NULL
* on failure.
*/
AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size);
/**
* Allocate a complete AVContentLightMetadata and add it to the frame.
*
* @param frame The frame which side data is added to.
*
* @return The AVContentLightMetadata structure to be filled by caller.
*/
AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *frame);
#endif /* AVUTIL_MASTERING_DISPLAY_METADATA_H */

Просмотреть файл

@ -65,6 +65,10 @@ if not CONFIG['MOZ_FFVPX_AUDIOONLY']:
'timecode.c',
'video_enc_params.c'
]
if CONFIG["MOZ_AV1"]:
SOURCES += [
'mastering_display_metadata.c',
]
SYMBOLS_FILE = 'avutil.symbols'
NoVisibilityFlags()