mirror of https://git.ffmpeg.org/ffmpeg.git
avcodec: remove deprecated FF_CODEC_CRYSTAL_HD
Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
parent
98e1eebef9
commit
5b23b18d40
|
@ -1930,7 +1930,6 @@ EXTERNAL_LIBRARY_LIST="
|
|||
HWACCEL_AUTODETECT_LIBRARY_LIST="
|
||||
amf
|
||||
audiotoolbox
|
||||
crystalhd
|
||||
cuda
|
||||
cuda_llvm
|
||||
cuvid
|
||||
|
@ -3066,7 +3065,6 @@ zmbv_decoder_select="inflate_wrapper"
|
|||
zmbv_encoder_select="deflate_wrapper"
|
||||
|
||||
# hardware accelerators
|
||||
crystalhd_deps="libcrystalhd_libcrystalhd_if_h"
|
||||
cuda_deps="ffnvcodec"
|
||||
cuvid_deps="ffnvcodec"
|
||||
d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext"
|
||||
|
@ -3259,7 +3257,6 @@ av1_nvenc_encoder_select="atsc_a53"
|
|||
h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m"
|
||||
h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m"
|
||||
h264_amf_encoder_deps="amf"
|
||||
h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser"
|
||||
h264_cuvid_decoder_deps="cuvid"
|
||||
h264_cuvid_decoder_select="h264_mp4toannexb_bsf"
|
||||
h264_mediacodec_decoder_deps="mediacodec"
|
||||
|
@ -3307,7 +3304,6 @@ mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode"
|
|||
mp3_mf_encoder_deps="mediafoundation"
|
||||
mpeg1_cuvid_decoder_deps="cuvid"
|
||||
mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m"
|
||||
mpeg2_crystalhd_decoder_select="crystalhd"
|
||||
mpeg2_cuvid_decoder_deps="cuvid"
|
||||
mpeg2_mmal_decoder_deps="mmal"
|
||||
mpeg2_mediacodec_decoder_deps="mediacodec"
|
||||
|
@ -3315,7 +3311,6 @@ mpeg2_qsv_decoder_select="qsvdec"
|
|||
mpeg2_qsv_encoder_select="qsvenc"
|
||||
mpeg2_vaapi_encoder_select="cbs_mpeg2 vaapi_encode"
|
||||
mpeg2_v4l2m2m_decoder_deps="v4l2_m2m mpeg2_v4l2_m2m"
|
||||
mpeg4_crystalhd_decoder_select="crystalhd"
|
||||
mpeg4_cuvid_decoder_deps="cuvid"
|
||||
mpeg4_mediacodec_decoder_deps="mediacodec"
|
||||
mpeg4_mediacodec_encoder_deps="mediacodec"
|
||||
|
@ -3323,8 +3318,6 @@ mpeg4_mmal_decoder_deps="mmal"
|
|||
mpeg4_omx_encoder_deps="omx"
|
||||
mpeg4_v4l2m2m_decoder_deps="v4l2_m2m mpeg4_v4l2_m2m"
|
||||
mpeg4_v4l2m2m_encoder_deps="v4l2_m2m mpeg4_v4l2_m2m"
|
||||
msmpeg4_crystalhd_decoder_select="crystalhd"
|
||||
vc1_crystalhd_decoder_select="crystalhd"
|
||||
vc1_cuvid_decoder_deps="cuvid"
|
||||
vc1_mmal_decoder_deps="mmal"
|
||||
vc1_qsv_decoder_select="qsvdec"
|
||||
|
@ -3348,7 +3341,6 @@ vp9_vaapi_encoder_select="vaapi_encode"
|
|||
vp9_qsv_encoder_deps="libmfx MFX_CODEC_VP9"
|
||||
vp9_qsv_encoder_select="qsvenc"
|
||||
vp9_v4l2m2m_decoder_deps="v4l2_m2m vp9_v4l2_m2m"
|
||||
wmv3_crystalhd_decoder_select="crystalhd"
|
||||
av1_qsv_decoder_select="qsvdec"
|
||||
av1_qsv_encoder_select="qsvenc"
|
||||
av1_qsv_encoder_deps="libvpl"
|
||||
|
@ -6532,7 +6524,6 @@ enabled libdrm &&
|
|||
check_headers linux/dma-buf.h
|
||||
|
||||
check_headers linux/perf_event.h
|
||||
check_headers libcrystalhd/libcrystalhd_if.h
|
||||
check_headers malloc.h
|
||||
check_headers mftransform.h
|
||||
check_headers net/udplite.h
|
||||
|
@ -7237,10 +7228,6 @@ enabled vdpau &&
|
|||
enabled vdpau &&
|
||||
check_lib vdpau_x11 "vdpau/vdpau.h vdpau/vdpau_x11.h" vdp_device_create_x11 -lvdpau -lX11
|
||||
|
||||
enabled crystalhd && check_lib crystalhd "stdint.h libcrystalhd/libcrystalhd_if.h" DtsCrystalHDVersion -lcrystalhd && \
|
||||
warn "CrystalHD support is deprecated and will be removed, please contact the developers if you are interested" \
|
||||
"in maintaining it."
|
||||
|
||||
if enabled vulkan; then
|
||||
check_pkg_config_header_only vulkan "vulkan >= 1.3.255" "vulkan/vulkan.h" "defined VK_VERSION_1_3" ||
|
||||
check_cpp_condition vulkan "vulkan/vulkan.h" "defined(VK_VERSION_1_4) || (defined(VK_VERSION_1_3) && VK_HEADER_VERSION >= 255)"
|
||||
|
|
|
@ -85,7 +85,6 @@ OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o
|
|||
OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o
|
||||
OBJS-$(CONFIG_CBS_VP8) += cbs_vp8.o vp8data.o
|
||||
OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o
|
||||
OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o
|
||||
OBJS-$(CONFIG_DEFLATE_WRAPPER) += zlib_wrapper.o
|
||||
OBJS-$(CONFIG_DOVI_RPU) += dovi_rpu.o
|
||||
OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o
|
||||
|
|
|
@ -148,7 +148,6 @@ extern const FFCodec ff_h263p_encoder;
|
|||
extern const FFCodec ff_h263p_decoder;
|
||||
extern const FFCodec ff_h263_v4l2m2m_decoder;
|
||||
extern const FFCodec ff_h264_decoder;
|
||||
extern const FFCodec ff_h264_crystalhd_decoder;
|
||||
extern const FFCodec ff_h264_v4l2m2m_decoder;
|
||||
extern const FFCodec ff_h264_mediacodec_decoder;
|
||||
extern const FFCodec ff_h264_mediacodec_encoder;
|
||||
|
@ -207,13 +206,11 @@ extern const FFCodec ff_mpeg2video_encoder;
|
|||
extern const FFCodec ff_mpeg2video_decoder;
|
||||
extern const FFCodec ff_mpeg4_encoder;
|
||||
extern const FFCodec ff_mpeg4_decoder;
|
||||
extern const FFCodec ff_mpeg4_crystalhd_decoder;
|
||||
extern const FFCodec ff_mpeg4_v4l2m2m_decoder;
|
||||
extern const FFCodec ff_mpeg4_mmal_decoder;
|
||||
extern const FFCodec ff_mpegvideo_decoder;
|
||||
extern const FFCodec ff_mpeg1_v4l2m2m_decoder;
|
||||
extern const FFCodec ff_mpeg2_mmal_decoder;
|
||||
extern const FFCodec ff_mpeg2_crystalhd_decoder;
|
||||
extern const FFCodec ff_mpeg2_v4l2m2m_decoder;
|
||||
extern const FFCodec ff_mpeg2_qsv_decoder;
|
||||
extern const FFCodec ff_mpeg2_mediacodec_decoder;
|
||||
|
@ -224,7 +221,6 @@ extern const FFCodec ff_msmpeg4v2_encoder;
|
|||
extern const FFCodec ff_msmpeg4v2_decoder;
|
||||
extern const FFCodec ff_msmpeg4v3_encoder;
|
||||
extern const FFCodec ff_msmpeg4v3_decoder;
|
||||
extern const FFCodec ff_msmpeg4_crystalhd_decoder;
|
||||
extern const FFCodec ff_msp2_decoder;
|
||||
extern const FFCodec ff_msrle_encoder;
|
||||
extern const FFCodec ff_msrle_decoder;
|
||||
|
@ -361,7 +357,6 @@ extern const FFCodec ff_vbn_encoder;
|
|||
extern const FFCodec ff_vbn_decoder;
|
||||
extern const FFCodec ff_vble_decoder;
|
||||
extern const FFCodec ff_vc1_decoder;
|
||||
extern const FFCodec ff_vc1_crystalhd_decoder;
|
||||
extern const FFCodec ff_vc1image_decoder;
|
||||
extern const FFCodec ff_vc1_mmal_decoder;
|
||||
extern const FFCodec ff_vc1_qsv_decoder;
|
||||
|
@ -398,7 +393,6 @@ extern const FFCodec ff_wmv1_decoder;
|
|||
extern const FFCodec ff_wmv2_encoder;
|
||||
extern const FFCodec ff_wmv2_decoder;
|
||||
extern const FFCodec ff_wmv3_decoder;
|
||||
extern const FFCodec ff_wmv3_crystalhd_decoder;
|
||||
extern const FFCodec ff_wmv3image_decoder;
|
||||
extern const FFCodec ff_wnv1_decoder;
|
||||
extern const FFCodec ff_xan_wc3_decoder;
|
||||
|
|
|
@ -1,825 +0,0 @@
|
|||
/*
|
||||
* - CrystalHD decoder module -
|
||||
*
|
||||
* Copyright(C) 2010,2011 Philip Langdale <ffmpeg.philipl@overt.org>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* - Principles of Operation -
|
||||
*
|
||||
* The CrystalHD decoder operates at the bitstream level - which is an even
|
||||
* higher level than the decoding hardware you typically see in modern GPUs.
|
||||
* This means it has a very simple interface, in principle. You feed demuxed
|
||||
* packets in one end and get decoded picture (fields/frames) out the other.
|
||||
*
|
||||
* Of course, nothing is ever that simple. Due, at the very least, to b-frame
|
||||
* dependencies in the supported formats, the hardware has a delay between
|
||||
* when a packet goes in, and when a picture comes out. Furthermore, this delay
|
||||
* is not just a function of time, but also one of the dependency on additional
|
||||
* frames being fed into the decoder to satisfy the b-frame dependencies.
|
||||
*
|
||||
* As such, the hardware can only be used effectively with a decode API that
|
||||
* doesn't assume a 1:1 relationship between input packets and output frames.
|
||||
* The new avcodec decode API is such an API (an m:n API) while the old one is
|
||||
* 1:1. Consequently, we no longer support the old API, which allows us to avoid
|
||||
* the vicious hacks that are required to approximate 1:1 operation.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* Includes
|
||||
****************************************************************************/
|
||||
|
||||
#include "config_components.h"
|
||||
|
||||
#define _XOPEN_SOURCE 600
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <libcrystalhd/bc_dts_types.h>
|
||||
#include <libcrystalhd/bc_dts_defs.h>
|
||||
#include <libcrystalhd/libcrystalhd_if.h>
|
||||
|
||||
#include "avcodec.h"
|
||||
#include "codec_internal.h"
|
||||
#include "decode.h"
|
||||
#include "internal.h"
|
||||
#include "libavutil/imgutils.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/opt.h"
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/** Timeout parameter passed to DtsProcOutput() in us */
|
||||
#define OUTPUT_PROC_TIMEOUT 50
|
||||
/** Step between fake timestamps passed to hardware in units of 100ns */
|
||||
#define TIMESTAMP_UNIT 100000
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Module private data
|
||||
****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
RET_ERROR = -1,
|
||||
RET_OK = 0,
|
||||
RET_COPY_AGAIN = 1,
|
||||
} CopyRet;
|
||||
|
||||
typedef struct OpaqueList {
|
||||
struct OpaqueList *next;
|
||||
uint64_t fake_timestamp;
|
||||
uint64_t reordered_opaque;
|
||||
} OpaqueList;
|
||||
|
||||
typedef struct {
|
||||
AVClass *av_class;
|
||||
AVCodecContext *avctx;
|
||||
/* This packet coincides with AVCodecInternal.in_pkt
|
||||
* and is not owned by us. */
|
||||
AVPacket *pkt;
|
||||
HANDLE dev;
|
||||
|
||||
uint8_t is_70012;
|
||||
uint8_t need_second_field;
|
||||
uint8_t draining;
|
||||
|
||||
OpaqueList *head;
|
||||
OpaqueList *tail;
|
||||
|
||||
/* Options */
|
||||
uint32_t sWidth;
|
||||
} CHDContext;
|
||||
|
||||
static const AVOption options[] = {
|
||||
{ "crystalhd_downscale_width",
|
||||
"Turn on downscaling to the specified width",
|
||||
offsetof(CHDContext, sWidth),
|
||||
AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT32_MAX,
|
||||
AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM, },
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Helper functions
|
||||
****************************************************************************/
|
||||
|
||||
static inline BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id)
|
||||
{
|
||||
switch (id) {
|
||||
case AV_CODEC_ID_MPEG4:
|
||||
return BC_MSUBTYPE_DIVX;
|
||||
case AV_CODEC_ID_MSMPEG4V3:
|
||||
return BC_MSUBTYPE_DIVX311;
|
||||
case AV_CODEC_ID_MPEG2VIDEO:
|
||||
return BC_MSUBTYPE_MPEG2VIDEO;
|
||||
case AV_CODEC_ID_VC1:
|
||||
return BC_MSUBTYPE_VC1;
|
||||
case AV_CODEC_ID_WMV3:
|
||||
return BC_MSUBTYPE_WMV3;
|
||||
case AV_CODEC_ID_H264:
|
||||
return BC_MSUBTYPE_H264;
|
||||
default:
|
||||
return BC_MSUBTYPE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void print_frame_info(CHDContext *priv, BC_DTS_PROC_OUT *output)
|
||||
{
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tYBuffSz: %u\n", output->YbuffSz);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tYBuffDoneSz: %u\n",
|
||||
output->YBuffDoneSz);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tUVBuffDoneSz: %u\n",
|
||||
output->UVBuffDoneSz);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tTimestamp: %"PRIu64"\n",
|
||||
output->PicInfo.timeStamp);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tPicture Number: %u\n",
|
||||
output->PicInfo.picture_number);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tWidth: %u\n",
|
||||
output->PicInfo.width);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tHeight: %u\n",
|
||||
output->PicInfo.height);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tChroma: 0x%03x\n",
|
||||
output->PicInfo.chroma_format);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tPulldown: %u\n",
|
||||
output->PicInfo.pulldown);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tFlags: 0x%08x\n",
|
||||
output->PicInfo.flags);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tFrame Rate/Res: %u\n",
|
||||
output->PicInfo.frame_rate);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tAspect Ratio: %u\n",
|
||||
output->PicInfo.aspect_ratio);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tColor Primaries: %u\n",
|
||||
output->PicInfo.colour_primaries);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tMetaData: %u\n",
|
||||
output->PicInfo.picture_meta_payload);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tSession Number: %u\n",
|
||||
output->PicInfo.sess_num);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tycom: %u\n",
|
||||
output->PicInfo.ycom);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tCustom Aspect: %u\n",
|
||||
output->PicInfo.custom_aspect_ratio_width_height);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tFrames to Drop: %u\n",
|
||||
output->PicInfo.n_drop);
|
||||
av_log(priv->avctx, AV_LOG_TRACE, "\tH264 Valid Fields: 0x%08x\n",
|
||||
output->PicInfo.other.h264.valid);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* OpaqueList functions
|
||||
****************************************************************************/
|
||||
|
||||
static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque)
|
||||
{
|
||||
OpaqueList *newNode = av_mallocz(sizeof (OpaqueList));
|
||||
if (!newNode) {
|
||||
av_log(priv->avctx, AV_LOG_ERROR,
|
||||
"Unable to allocate new node in OpaqueList.\n");
|
||||
return 0;
|
||||
}
|
||||
if (!priv->head) {
|
||||
newNode->fake_timestamp = TIMESTAMP_UNIT;
|
||||
priv->head = newNode;
|
||||
} else {
|
||||
newNode->fake_timestamp = priv->tail->fake_timestamp + TIMESTAMP_UNIT;
|
||||
priv->tail->next = newNode;
|
||||
}
|
||||
priv->tail = newNode;
|
||||
newNode->reordered_opaque = reordered_opaque;
|
||||
|
||||
return newNode->fake_timestamp;
|
||||
}
|
||||
|
||||
/*
|
||||
* The OpaqueList is built in decode order, while elements will be removed
|
||||
* in presentation order. If frames are reordered, this means we must be
|
||||
* able to remove elements that are not the first element.
|
||||
*
|
||||
* Returned node must be freed by caller.
|
||||
*/
|
||||
static OpaqueList *opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp)
|
||||
{
|
||||
OpaqueList *node = priv->head;
|
||||
|
||||
if (!priv->head) {
|
||||
av_log(priv->avctx, AV_LOG_ERROR,
|
||||
"CrystalHD: Attempted to query non-existent timestamps.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The first element is special-cased because we have to manipulate
|
||||
* the head pointer rather than the previous element in the list.
|
||||
*/
|
||||
if (priv->head->fake_timestamp == fake_timestamp) {
|
||||
priv->head = node->next;
|
||||
|
||||
if (!priv->head->next)
|
||||
priv->tail = priv->head;
|
||||
|
||||
node->next = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* The list is processed at arm's length so that we have the
|
||||
* previous element available to rewrite its next pointer.
|
||||
*/
|
||||
while (node->next) {
|
||||
OpaqueList *current = node->next;
|
||||
if (current->fake_timestamp == fake_timestamp) {
|
||||
node->next = current->next;
|
||||
|
||||
if (!node->next)
|
||||
priv->tail = node;
|
||||
|
||||
current->next = NULL;
|
||||
return current;
|
||||
} else {
|
||||
node = current;
|
||||
}
|
||||
}
|
||||
|
||||
av_log(priv->avctx, AV_LOG_VERBOSE,
|
||||
"CrystalHD: Couldn't match fake_timestamp.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Video decoder API function definitions
|
||||
****************************************************************************/
|
||||
|
||||
static void flush(AVCodecContext *avctx)
|
||||
{
|
||||
CHDContext *priv = avctx->priv_data;
|
||||
|
||||
priv->need_second_field = 0;
|
||||
priv->draining = 0;
|
||||
|
||||
/* Flush mode 4 flushes all software and hardware buffers. */
|
||||
DtsFlushInput(priv->dev, 4);
|
||||
}
|
||||
|
||||
|
||||
static av_cold int uninit(AVCodecContext *avctx)
|
||||
{
|
||||
CHDContext *priv = avctx->priv_data;
|
||||
HANDLE device;
|
||||
|
||||
device = priv->dev;
|
||||
DtsStopDecoder(device);
|
||||
DtsCloseDecoder(device);
|
||||
DtsDeviceClose(device);
|
||||
|
||||
if (priv->head) {
|
||||
OpaqueList *node = priv->head;
|
||||
while (node) {
|
||||
OpaqueList *next = node->next;
|
||||
av_free(node);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static av_cold int init(AVCodecContext *avctx)
|
||||
{
|
||||
CHDContext* priv;
|
||||
BC_STATUS ret;
|
||||
BC_INFO_CRYSTAL version;
|
||||
BC_INPUT_FORMAT format = {
|
||||
.FGTEnable = FALSE,
|
||||
.Progressive = TRUE,
|
||||
.OptFlags = 0x80000000 | vdecFrameRate59_94 | 0x40,
|
||||
.width = avctx->width,
|
||||
.height = avctx->height,
|
||||
};
|
||||
|
||||
BC_MEDIA_SUBTYPE subtype;
|
||||
|
||||
uint32_t mode = DTS_PLAYBACK_MODE |
|
||||
DTS_LOAD_FILE_PLAY_FW |
|
||||
DTS_SKIP_TX_CHK_CPB |
|
||||
DTS_PLAYBACK_DROP_RPT_MODE |
|
||||
DTS_SINGLE_THREADED_MODE |
|
||||
DTS_DFLT_RESOLUTION(vdecRESOLUTION_1080p23_976);
|
||||
|
||||
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD Init for %s\n",
|
||||
avctx->codec->name);
|
||||
|
||||
av_log(avctx, AV_LOG_WARNING, "CrystalHD support is deprecated and will "
|
||||
"be removed. Please contact the developers if you are interested in "
|
||||
"maintaining it.\n");
|
||||
|
||||
avctx->pix_fmt = AV_PIX_FMT_YUYV422;
|
||||
|
||||
/* Initialize the library */
|
||||
priv = avctx->priv_data;
|
||||
priv->avctx = avctx;
|
||||
priv->pkt = avctx->internal->in_pkt;
|
||||
priv->draining = 0;
|
||||
|
||||
subtype = id2subtype(priv, avctx->codec->id);
|
||||
switch (subtype) {
|
||||
case BC_MSUBTYPE_H264:
|
||||
format.startCodeSz = 4;
|
||||
// Fall-through
|
||||
case BC_MSUBTYPE_VC1:
|
||||
case BC_MSUBTYPE_WVC1:
|
||||
case BC_MSUBTYPE_WMV3:
|
||||
case BC_MSUBTYPE_WMVA:
|
||||
case BC_MSUBTYPE_MPEG2VIDEO:
|
||||
case BC_MSUBTYPE_DIVX:
|
||||
case BC_MSUBTYPE_DIVX311:
|
||||
format.pMetaData = avctx->extradata;
|
||||
format.metaDataSz = avctx->extradata_size;
|
||||
break;
|
||||
default:
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: Unknown codec name\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
format.mSubtype = subtype;
|
||||
|
||||
if (priv->sWidth) {
|
||||
format.bEnableScaling = 1;
|
||||
format.ScalingParams.sWidth = priv->sWidth;
|
||||
}
|
||||
|
||||
/* Get a decoder instance */
|
||||
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: starting up\n");
|
||||
// Initialize the Link and Decoder devices
|
||||
ret = DtsDeviceOpen(&priv->dev, mode);
|
||||
if (ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: DtsDeviceOpen failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = DtsCrystalHDVersion(priv->dev, &version);
|
||||
if (ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_VERBOSE,
|
||||
"CrystalHD: DtsCrystalHDVersion failed\n");
|
||||
goto fail;
|
||||
}
|
||||
priv->is_70012 = version.device == 0;
|
||||
|
||||
if (priv->is_70012 &&
|
||||
(subtype == BC_MSUBTYPE_DIVX || subtype == BC_MSUBTYPE_DIVX311)) {
|
||||
av_log(avctx, AV_LOG_VERBOSE,
|
||||
"CrystalHD: BCM70012 doesn't support MPEG4-ASP/DivX/Xvid\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = DtsSetInputFormat(priv->dev, &format);
|
||||
if (ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: SetInputFormat failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = DtsOpenDecoder(priv->dev, BC_STREAM_TYPE_ES);
|
||||
if (ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsOpenDecoder failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = DtsSetColorSpace(priv->dev, OUTPUT_MODE422_YUY2);
|
||||
if (ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsSetColorSpace failed\n");
|
||||
goto fail;
|
||||
}
|
||||
ret = DtsStartDecoder(priv->dev);
|
||||
if (ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartDecoder failed\n");
|
||||
goto fail;
|
||||
}
|
||||
ret = DtsStartCapture(priv->dev);
|
||||
if (ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartCapture failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Init complete.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
uninit(avctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static inline CopyRet copy_frame(AVCodecContext *avctx,
|
||||
BC_DTS_PROC_OUT *output,
|
||||
AVFrame *frame, int *got_frame)
|
||||
{
|
||||
BC_STATUS ret;
|
||||
BC_DTS_STATUS decoder_status = { 0, };
|
||||
uint8_t interlaced;
|
||||
|
||||
CHDContext *priv = avctx->priv_data;
|
||||
int64_t pkt_pts = AV_NOPTS_VALUE;
|
||||
|
||||
uint8_t bottom_field = (output->PicInfo.flags & VDEC_FLAG_BOTTOMFIELD) ==
|
||||
VDEC_FLAG_BOTTOMFIELD;
|
||||
uint8_t bottom_first = !!(output->PicInfo.flags & VDEC_FLAG_BOTTOM_FIRST);
|
||||
|
||||
int width = output->PicInfo.width;
|
||||
int height = output->PicInfo.height;
|
||||
int bwidth;
|
||||
uint8_t *src = output->Ybuff;
|
||||
int sStride;
|
||||
uint8_t *dst;
|
||||
int dStride;
|
||||
|
||||
if (output->PicInfo.timeStamp != 0) {
|
||||
OpaqueList *node = opaque_list_pop(priv, output->PicInfo.timeStamp);
|
||||
if (node) {
|
||||
pkt_pts = node->reordered_opaque;
|
||||
av_free(node);
|
||||
} else {
|
||||
/*
|
||||
* We will encounter a situation where a timestamp cannot be
|
||||
* popped if a second field is being returned. In this case,
|
||||
* each field has the same timestamp and the first one will
|
||||
* cause it to be popped. We'll avoid overwriting the valid
|
||||
* timestamp below.
|
||||
*/
|
||||
}
|
||||
av_log(avctx, AV_LOG_VERBOSE, "output \"pts\": %"PRIu64"\n",
|
||||
output->PicInfo.timeStamp);
|
||||
}
|
||||
|
||||
ret = DtsGetDriverStatus(priv->dev, &decoder_status);
|
||||
if (ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR,
|
||||
"CrystalHD: GetDriverStatus failed: %u\n", ret);
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
interlaced = output->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC;
|
||||
|
||||
av_log(avctx, AV_LOG_VERBOSE, "Interlaced state: %d\n",
|
||||
interlaced);
|
||||
|
||||
priv->need_second_field = interlaced && !priv->need_second_field;
|
||||
|
||||
if (!frame->data[0]) {
|
||||
if (ff_get_buffer(avctx, frame, 0) < 0)
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
bwidth = av_image_get_linesize(avctx->pix_fmt, width, 0);
|
||||
if (bwidth < 0)
|
||||
return RET_ERROR;
|
||||
|
||||
if (priv->is_70012) {
|
||||
int pStride;
|
||||
|
||||
if (width <= 720)
|
||||
pStride = 720;
|
||||
else if (width <= 1280)
|
||||
pStride = 1280;
|
||||
else pStride = 1920;
|
||||
sStride = av_image_get_linesize(avctx->pix_fmt, pStride, 0);
|
||||
if (sStride < 0)
|
||||
return RET_ERROR;
|
||||
} else {
|
||||
sStride = bwidth;
|
||||
}
|
||||
|
||||
dStride = frame->linesize[0];
|
||||
dst = frame->data[0];
|
||||
|
||||
av_log(priv->avctx, AV_LOG_VERBOSE, "CrystalHD: Copying out frame\n");
|
||||
|
||||
/*
|
||||
* The hardware doesn't return the first sample of a picture.
|
||||
* Ignoring why it behaves this way, it's better to copy the sample from
|
||||
* the second line, rather than the next sample across because the chroma
|
||||
* values should be correct (assuming the decoded video was 4:2:0, which
|
||||
* it was).
|
||||
*/
|
||||
*((uint32_t *)src) = *((uint32_t *)(src + sStride));
|
||||
|
||||
if (interlaced) {
|
||||
int dY = 0;
|
||||
int sY = 0;
|
||||
|
||||
height /= 2;
|
||||
if (bottom_field) {
|
||||
av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: bottom field\n");
|
||||
dY = 1;
|
||||
} else {
|
||||
av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: top field\n");
|
||||
dY = 0;
|
||||
}
|
||||
|
||||
for (sY = 0; sY < height; dY++, sY++) {
|
||||
memcpy(&(dst[dY * dStride]), &(src[sY * sStride]), bwidth);
|
||||
dY++;
|
||||
}
|
||||
} else {
|
||||
av_image_copy_plane(dst, dStride, src, sStride, bwidth, height);
|
||||
}
|
||||
|
||||
frame->flags |= AV_FRAME_FLAG_INTERLACED * !!interlaced;
|
||||
if (interlaced)
|
||||
frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * !bottom_first;
|
||||
|
||||
frame->pts = pkt_pts;
|
||||
|
||||
frame->duration = 0;
|
||||
#if FF_API_FRAME_PKT
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
frame->pkt_pos = -1;
|
||||
frame->pkt_size = -1;
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
|
||||
if (!priv->need_second_field) {
|
||||
*got_frame = 1;
|
||||
} else {
|
||||
return RET_COPY_AGAIN;
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
|
||||
static inline CopyRet receive_frame(AVCodecContext *avctx,
|
||||
AVFrame *frame, int *got_frame)
|
||||
{
|
||||
BC_STATUS ret;
|
||||
BC_DTS_PROC_OUT output = {
|
||||
.PicInfo.width = avctx->width,
|
||||
.PicInfo.height = avctx->height,
|
||||
};
|
||||
CHDContext *priv = avctx->priv_data;
|
||||
HANDLE dev = priv->dev;
|
||||
|
||||
*got_frame = 0;
|
||||
|
||||
// Request decoded data from the driver
|
||||
ret = DtsProcOutputNoCopy(dev, OUTPUT_PROC_TIMEOUT, &output);
|
||||
if (ret == BC_STS_FMT_CHANGE) {
|
||||
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Initial format change\n");
|
||||
avctx->width = output.PicInfo.width;
|
||||
avctx->height = output.PicInfo.height;
|
||||
switch ( output.PicInfo.aspect_ratio ) {
|
||||
case vdecAspectRatioSquare:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 1, 1};
|
||||
break;
|
||||
case vdecAspectRatio12_11:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 12, 11};
|
||||
break;
|
||||
case vdecAspectRatio10_11:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 10, 11};
|
||||
break;
|
||||
case vdecAspectRatio16_11:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 16, 11};
|
||||
break;
|
||||
case vdecAspectRatio40_33:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 40, 33};
|
||||
break;
|
||||
case vdecAspectRatio24_11:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 24, 11};
|
||||
break;
|
||||
case vdecAspectRatio20_11:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 20, 11};
|
||||
break;
|
||||
case vdecAspectRatio32_11:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 32, 11};
|
||||
break;
|
||||
case vdecAspectRatio80_33:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 80, 33};
|
||||
break;
|
||||
case vdecAspectRatio18_11:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 18, 11};
|
||||
break;
|
||||
case vdecAspectRatio15_11:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 15, 11};
|
||||
break;
|
||||
case vdecAspectRatio64_33:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 64, 33};
|
||||
break;
|
||||
case vdecAspectRatio160_99:
|
||||
avctx->sample_aspect_ratio = (AVRational) {160, 99};
|
||||
break;
|
||||
case vdecAspectRatio4_3:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 4, 3};
|
||||
break;
|
||||
case vdecAspectRatio16_9:
|
||||
avctx->sample_aspect_ratio = (AVRational) { 16, 9};
|
||||
break;
|
||||
case vdecAspectRatio221_1:
|
||||
avctx->sample_aspect_ratio = (AVRational) {221, 1};
|
||||
break;
|
||||
}
|
||||
return RET_COPY_AGAIN;
|
||||
} else if (ret == BC_STS_SUCCESS) {
|
||||
int copy_ret = -1;
|
||||
if (output.PoutFlags & BC_POUT_FLAGS_PIB_VALID) {
|
||||
print_frame_info(priv, &output);
|
||||
|
||||
copy_ret = copy_frame(avctx, &output, frame, got_frame);
|
||||
} else {
|
||||
/*
|
||||
* An invalid frame has been consumed.
|
||||
*/
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput succeeded with "
|
||||
"invalid PIB\n");
|
||||
copy_ret = RET_COPY_AGAIN;
|
||||
}
|
||||
DtsReleaseOutputBuffs(dev, NULL, FALSE);
|
||||
|
||||
return copy_ret;
|
||||
} else if (ret == BC_STS_BUSY) {
|
||||
return RET_COPY_AGAIN;
|
||||
} else {
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput failed %d\n", ret);
|
||||
return RET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static int crystalhd_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
|
||||
{
|
||||
BC_STATUS bc_ret;
|
||||
CHDContext *priv = avctx->priv_data;
|
||||
HANDLE dev = priv->dev;
|
||||
int ret = 0;
|
||||
|
||||
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_packet\n");
|
||||
|
||||
if (avpkt && avpkt->size) {
|
||||
uint64_t pts;
|
||||
|
||||
/*
|
||||
* Despite being notionally opaque, either libcrystalhd or
|
||||
* the hardware itself will mangle pts values that are too
|
||||
* small or too large. The docs claim it should be in units
|
||||
* of 100ns. Given that we're nominally dealing with a black
|
||||
* box on both sides, any transform we do has no guarantee of
|
||||
* avoiding mangling so we need to build a mapping to values
|
||||
* we know will not be mangled.
|
||||
*/
|
||||
pts = opaque_list_push(priv, avpkt->pts);
|
||||
if (!pts) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto exit;
|
||||
}
|
||||
av_log(priv->avctx, AV_LOG_VERBOSE,
|
||||
"input \"pts\": %"PRIu64"\n", pts);
|
||||
bc_ret = DtsProcInput(dev, avpkt->data, avpkt->size, pts, 0);
|
||||
if (bc_ret == BC_STS_BUSY) {
|
||||
av_log(avctx, AV_LOG_WARNING,
|
||||
"CrystalHD: ProcInput returned busy\n");
|
||||
ret = AVERROR(EAGAIN);
|
||||
goto exit;
|
||||
} else if (bc_ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR,
|
||||
"CrystalHD: ProcInput failed: %u\n", ret);
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
av_log(avctx, AV_LOG_INFO, "CrystalHD: No more input data\n");
|
||||
priv->draining = 1;
|
||||
ret = AVERROR_EOF;
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
{
|
||||
BC_STATUS bc_ret;
|
||||
BC_DTS_STATUS decoder_status = { 0, };
|
||||
CopyRet rec_ret;
|
||||
CHDContext *priv = avctx->priv_data;
|
||||
AVPacket *const pkt = priv->pkt;
|
||||
HANDLE dev = priv->dev;
|
||||
int got_frame = 0;
|
||||
int ret = 0;
|
||||
|
||||
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: receive_frame\n");
|
||||
|
||||
ret = ff_decode_get_packet(avctx, pkt);
|
||||
if (ret < 0 && ret != AVERROR_EOF) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (pkt->size > DtsTxFreeSize(dev)) {
|
||||
/*
|
||||
* Block until there is space in the buffer for the next packet.
|
||||
* We assume that the hardware will make forward progress at this
|
||||
* point, although in pathological cases that may not happen.
|
||||
*/
|
||||
av_log(avctx, AV_LOG_TRACE, "CrystalHD: Waiting for space in input buffer\n");
|
||||
}
|
||||
|
||||
ret = crystalhd_decode_packet(avctx, pkt);
|
||||
av_packet_unref(pkt);
|
||||
// crystalhd_is_buffer_full() should avoid this.
|
||||
if (ret == AVERROR(EAGAIN)) {
|
||||
ret = AVERROR_EXTERNAL;
|
||||
}
|
||||
if (ret < 0 && ret != AVERROR_EOF) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
do {
|
||||
bc_ret = DtsGetDriverStatus(dev, &decoder_status);
|
||||
if (bc_ret != BC_STS_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR, "CrystalHD: GetDriverStatus failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (decoder_status.ReadyListCount == 0) {
|
||||
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Insufficient frames ready. Returning\n");
|
||||
got_frame = 0;
|
||||
rec_ret = RET_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
rec_ret = receive_frame(avctx, frame, &got_frame);
|
||||
} while (rec_ret == RET_COPY_AGAIN);
|
||||
|
||||
if (rec_ret == RET_ERROR) {
|
||||
return -1;
|
||||
} else if (got_frame == 0) {
|
||||
return priv->draining ? AVERROR_EOF : AVERROR(EAGAIN);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFINE_CRYSTALHD_DECODER(x, X, bsf_name) \
|
||||
static const AVClass x##_crystalhd_class = { \
|
||||
.class_name = #x "_crystalhd", \
|
||||
.item_name = av_default_item_name, \
|
||||
.option = options, \
|
||||
.version = LIBAVUTIL_VERSION_INT, \
|
||||
}; \
|
||||
const FFCodec ff_##x##_crystalhd_decoder = { \
|
||||
.p.name = #x "_crystalhd", \
|
||||
CODEC_LONG_NAME("CrystalHD " #X " decoder"), \
|
||||
.p.type = AVMEDIA_TYPE_VIDEO, \
|
||||
.p.id = AV_CODEC_ID_##X, \
|
||||
.priv_data_size = sizeof(CHDContext), \
|
||||
.p.priv_class = &x##_crystalhd_class, \
|
||||
.init = init, \
|
||||
.close = uninit, \
|
||||
FF_CODEC_RECEIVE_FRAME_CB(crystalhd_receive_frame), \
|
||||
.flush = flush, \
|
||||
.bsfs = bsf_name, \
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
|
||||
.caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | \
|
||||
FF_CODEC_CAP_SETS_FRAME_PROPS, \
|
||||
.p.wrapper_name = "crystalhd", \
|
||||
};
|
||||
|
||||
#if CONFIG_H264_CRYSTALHD_DECODER
|
||||
DEFINE_CRYSTALHD_DECODER(h264, H264, "h264_mp4toannexb")
|
||||
#endif
|
||||
|
||||
#if CONFIG_MPEG2_CRYSTALHD_DECODER
|
||||
DEFINE_CRYSTALHD_DECODER(mpeg2, MPEG2VIDEO, NULL)
|
||||
#endif
|
||||
|
||||
#if CONFIG_MPEG4_CRYSTALHD_DECODER
|
||||
DEFINE_CRYSTALHD_DECODER(mpeg4, MPEG4, "mpeg4_unpack_bframes")
|
||||
#endif
|
||||
|
||||
#if CONFIG_MSMPEG4_CRYSTALHD_DECODER
|
||||
DEFINE_CRYSTALHD_DECODER(msmpeg4, MSMPEG4V3, NULL)
|
||||
#endif
|
||||
|
||||
#if CONFIG_VC1_CRYSTALHD_DECODER
|
||||
DEFINE_CRYSTALHD_DECODER(vc1, VC1, NULL)
|
||||
#endif
|
||||
|
||||
#if CONFIG_WMV3_CRYSTALHD_DECODER
|
||||
DEFINE_CRYSTALHD_DECODER(wmv3, WMV3, NULL)
|
||||
#endif
|
|
@ -47,7 +47,4 @@
|
|||
#define FF_API_AVCODEC_CLOSE (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_BUFFER_MIN_SIZE (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
|
||||
// reminder to remove CrystalHD decoders on next major bump
|
||||
#define FF_CODEC_CRYSTAL_HD (LIBAVCODEC_VERSION_MAJOR < 61)
|
||||
|
||||
#endif /* AVCODEC_VERSION_MAJOR_H */
|
||||
|
|
Loading…
Reference in New Issue