зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
4354b92057
Коммит
03ec7b6a39
|
@ -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()
|
||||
|
|
Загрузка…
Ссылка в новой задаче