From d02ba80db1c4791db9e661e2ae4526041fee3b40 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 28 Jun 2021 07:51:02 +0800 Subject: [PATCH 1/2] Squash: Fix bug for building FFmpeg --- CHANGELOG.md | 2 + .../ffmpeg-4-fit/libavcodec/crystalhd.c | 814 ++++++++++++++++++ trunk/auto/depends.sh | 7 +- trunk/src/core/srs_core_version4.hpp | 2 +- 4 files changed, 821 insertions(+), 4 deletions(-) create mode 100644 trunk/3rdparty/ffmpeg-4-fit/libavcodec/crystalhd.c diff --git a/CHANGELOG.md b/CHANGELOG.md index d5746b6a0..e89a58005 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ The changelog for SRS. ## SRS 4.0 Changelog +* v4.0, 2021-06-28, Fix [#2431](https://github.com/ossrs/srs/issues/2431), configure FFmpeg bug. 4.0.135 +* v4.0, 2021-06-28, Merge [#2444](https://github.com/ossrs/srs/pull/2444), add libavcodec/crystalhd.c for FFmpeg. 4.0.134 * v4.0, 2021-06-28, Merge [#2438](https://github.com/ossrs/srs/pull/2438), fix losing of last HLS ts file 4.0.133 * v4.0, 2021-06-27, Squash for [#2424](https://github.com/ossrs/srs/issues/2424), query the latest available version. 4.0.132 * v4.0, 2021-06-24, Merge [#2429](https://github.com/ossrs/srs/pull/2429) to fix SRT bug. 4.0.131 diff --git a/trunk/3rdparty/ffmpeg-4-fit/libavcodec/crystalhd.c b/trunk/3rdparty/ffmpeg-4-fit/libavcodec/crystalhd.c new file mode 100644 index 000000000..228803183 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4-fit/libavcodec/crystalhd.c @@ -0,0 +1,814 @@ +/* + * - CrystalHD decoder module - + * + * Copyright(C) 2010,2011 Philip Langdale + * + * 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 + ****************************************************************************/ + +#define _XOPEN_SOURCE 600 +#include +#include +#include + +#include +#include +#include + +#include "avcodec.h" +#include "decode.h" +#include "internal.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" + +#if HAVE_UNISTD_H +#include +#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; + 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); + + avctx->pix_fmt = AV_PIX_FMT_YUYV422; + + /* Initialize the library */ + priv = avctx->priv_data; + priv->avctx = avctx; + 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->interlaced_frame = interlaced; + if (interlaced) + frame->top_field_first = !bottom_first; + + frame->pts = pkt_pts; +#if FF_API_PKT_PTS +FF_DISABLE_DEPRECATION_WARNINGS + frame->pkt_pts = pkt_pts; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + frame->pkt_pos = -1; + frame->pkt_duration = 0; + frame->pkt_size = -1; + + 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; + HANDLE dev = priv->dev; + int got_frame = 0; + int ret = 0; + AVPacket pkt = {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, \ + }; \ + AVCodec ff_##x##_crystalhd_decoder = { \ + .name = #x "_crystalhd", \ + .long_name = NULL_IF_CONFIG_SMALL("CrystalHD " #X " decoder"), \ + .type = AVMEDIA_TYPE_VIDEO, \ + .id = AV_CODEC_ID_##X, \ + .priv_data_size = sizeof(CHDContext), \ + .priv_class = &x##_crystalhd_class, \ + .init = init, \ + .close = uninit, \ + .receive_frame = crystalhd_receive_frame, \ + .flush = flush, \ + .bsfs = bsf_name, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ + .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE}, \ + .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 diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index d259115f2..0bba98f8f 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -701,15 +701,16 @@ if [[ $SRS_FFMPEG_FIT == YES ]]; then cd ${SRS_OBJS}/${SRS_PLATFORM}/ffmpeg-4-fit && cp -R ../../../3rdparty/ffmpeg-4-fit/* . && # Build source code. $FFMPEG_CONFIGURE \ - --prefix=`pwd`/_release --pkg-config=pkg-config ${FFMPEG_OPTIONS} \ - --disable-everything --pkg-config-flags="--static" --extra-libs="-lpthread" --extra-libs="-lm" \ + --prefix=`pwd`/_release --pkg-config=pkg-config \ + --pkg-config-flags="--static" --extra-libs="-lpthread" --extra-libs="-lm" \ + --disable-everything ${FFMPEG_OPTIONS} \ --disable-programs --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages \ --disable-avdevice --disable-avformat --disable-swscale --disable-postproc --disable-avfilter --disable-network \ --disable-dct --disable-dwt --disable-error-resilience --disable-lsp --disable-lzo --disable-faan --disable-pixelutils \ --disable-hwaccels --disable-devices --disable-audiotoolbox --disable-videotoolbox --disable-cuvid \ --disable-d3d11va --disable-dxva2 --disable-ffnvcodec --disable-nvdec --disable-nvenc --disable-v4l2-m2m --disable-vaapi \ --disable-vdpau --disable-appkit --disable-coreimage --disable-avfoundation --disable-securetransport --disable-iconv \ - --disable-lzma --disable-sdl2 --disable-everything --enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm \ + --disable-lzma --disable-sdl2 --enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm \ --enable-encoder=aac && # See https://www.laoyuyu.me/2019/05/23/android/clang_compile_ffmpeg/ if [[ $SRS_CROSS_BUILD == YES ]]; then diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp index 4d44e09cc..7890accec 100644 --- a/trunk/src/core/srs_core_version4.hpp +++ b/trunk/src/core/srs_core_version4.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 4 #define VERSION_MINOR 0 -#define VERSION_REVISION 133 +#define VERSION_REVISION 135 #endif From f986b5956bc2f98d58f725bc6d7bf73aebf1f076 Mon Sep 17 00:00:00 2001 From: Xiaoniu Date: Mon, 28 Jun 2021 07:51:57 +0800 Subject: [PATCH 2/2] check 'vhost' validity in 'http raw dvr api' (#2435) --- trunk/src/app/srs_app_config.cpp | 8 ++++++++ trunk/src/app/srs_app_http_api.cpp | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index e2d8d698b..c60b1754b 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3171,6 +3171,8 @@ srs_error_t SrsConfig::raw_disable_vhost(string vhost, bool& applied) applied = false; SrsConfDirective* conf = root->get("vhost", vhost); + srs_assert(conf); + conf->get_or_create("enabled")->set_arg0("off"); if ((err = do_reload_vhost_removed(vhost)) != srs_success) { @@ -3189,6 +3191,8 @@ srs_error_t SrsConfig::raw_enable_vhost(string vhost, bool& applied) applied = false; SrsConfDirective* conf = root->get("vhost", vhost); + srs_assert(conf); + conf->get_or_create("enabled")->set_arg0("on"); if ((err = do_reload_vhost_added(vhost)) != srs_success) { @@ -3207,6 +3211,8 @@ srs_error_t SrsConfig::raw_enable_dvr(string vhost, string stream, bool& applied applied = false; SrsConfDirective* conf = root->get("vhost", vhost); + srs_assert(conf); + conf = conf->get_or_create("dvr")->get_or_create("dvr_apply"); if (conf->args.size() == 1 && (conf->arg0() == "all" || conf->arg0() == "none")) { @@ -3233,6 +3239,8 @@ srs_error_t SrsConfig::raw_disable_dvr(string vhost, string stream, bool& applie applied = false; SrsConfDirective* conf = root->get("vhost", vhost); + srs_assert(conf); + conf = conf->get_or_create("dvr")->get_or_create("dvr_apply"); std::vector::iterator it; diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 5087a825e..81c7add7e 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1206,7 +1206,12 @@ srs_error_t SrsGoApiRaw::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* if (action != "enable" && action != "disable") { return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_NOT_ALLOWED); } - + + // the vhost must exists. + if (!_srs_config->get_vhost(value, false)) { + return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_PARAMS); + } + if (!_srs_config->get_dvr_enabled(value)) { return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_NOT_ALLOWED); }