Add Chinese AVS2 video decoder, FFmpeg can make use of the libdavs2 library for AVS2 decoding.
Signed-off-by: hwren <hwr...@126.com> --- Changelog | 1 + configure | 6 ++ doc/general.texi | 8 ++ libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 ++ libavcodec/libdavs2.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++ libavformat/riff.c | 1 + 9 files changed, 242 insertions(+) create mode 100644 libavcodec/libdavs2.c diff --git a/Changelog b/Changelog index 3d25564..0f97679 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,7 @@ version <next>: - aderivative and aintegral audio filters - pal75bars and pal100bars video filter sources - support mbedTLS based TLS +- AVS2 video decoder version 4.0: diff --git a/configure b/configure index 09ff0c5..9aec00d 100755 --- a/configure +++ b/configure @@ -276,6 +276,7 @@ External library support: --enable-libx264 enable H.264 encoding via x264 [no] --enable-libx265 enable HEVC encoding via x265 [no] --enable-libxavs enable AVS encoding via xavs [no] + --enable-libdavs2 enable AVS2 decoding via davs2 [no] --enable-libxcb enable X11 grabbing using XCB [autodetect] --enable-libxcb-shm enable X11 grabbing shm communication [autodetect] --enable-libxcb-xfixes enable X11 grabbing mouse rendering [autodetect] @@ -1641,6 +1642,7 @@ EXTERNAL_LIBRARY_GPL_LIST=" libx264 libx265 libxavs + libdavs2 libxvid " @@ -3095,6 +3097,7 @@ libx264rgb_encoder_deps="libx264 x264_csp_bgr" libx264rgb_encoder_select="libx264_encoder" libx265_encoder_deps="libx265" libxavs_encoder_deps="libxavs" +libdavs2_decoder_deps="libdavs2" libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" vapoursynth_demuxer_deps="vapoursynth" @@ -6104,6 +6107,9 @@ enabled libx264 && { check_pkg_config libx264 x264 "stdint.h x264.h" x enabled libx265 && require_pkg_config libx265 x265 x265.h x265_api_get && require_cpp_condition x265.h "X265_BUILD >= 68" enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs" +enabled libdavs2 && require_pkg_config libdavs2 davs2 "stdint.h davs2.h" davs2_decoder_decode && + { check_cpp_condition davs2 davs2.h "DAVS2_BUILD >= 12" || + die "ERROR: libdavs2 version must be >= 12." ; } enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore enabled libzimg && require_pkg_config libzimg "zimg >= 2.7.0" zimg.h zimg_get_api_version enabled libzmq && require_pkg_config libzmq libzmq zmq.h zmq_ctx_new diff --git a/doc/general.texi b/doc/general.texi index 2583006..d3c1503 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -17,6 +17,14 @@ for more formats. None of them are used by default, their use has to be explicitly requested by passing the appropriate flags to @command{./configure}. +@section libdavs2 + +FFmpeg can make use of the libdavs2 library for AVS2 decoding. + +Go to @url{https://github.com/pkuvcl/davs2} and follow the instructions for +installing the library. Then pass @code{--enable-libdavs2} to configure to +enable it. + @section Alliance for Open Media libaom FFmpeg can make use of the libaom library for AV1 decoding. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 3ab071a..e85b74c 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -985,6 +985,7 @@ OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o +OBJS-$(CONFIG_LIBDAVS2_DECODER) += libdavs2.o OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o OBJS-$(CONFIG_LIBZVBI_TELETEXT_DECODER) += libzvbi-teletextdec.o ass.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 7b7a8c7..6103081 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -705,6 +705,7 @@ extern AVCodec ff_libx264_encoder; extern AVCodec ff_libx264rgb_encoder; extern AVCodec ff_libx265_encoder; extern AVCodec ff_libxavs_encoder; +extern AVCodec ff_libdavs2_decoder; extern AVCodec ff_libxvid_encoder; extern AVCodec ff_libzvbi_teletext_decoder; diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index fb0c6fa..a8cbc7b 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -303,6 +303,7 @@ enum AVCodecID { AV_CODEC_ID_KMVC, AV_CODEC_ID_FLASHSV, AV_CODEC_ID_CAVS, + AV_CODEC_ID_AVS2, AV_CODEC_ID_JPEG2000, AV_CODEC_ID_VMNC, AV_CODEC_ID_VP5, diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 79552a9..9b50dae 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -651,6 +651,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, }, { + .id = AV_CODEC_ID_AVS2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "avs2", + .long_name = NULL_IF_CONFIG_SMALL("Chinese AVS2 (Audio Video Standar) (AVS2-P2, JiZhun profile)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { .id = AV_CODEC_ID_JPEG2000, .type = AVMEDIA_TYPE_VIDEO, .name = "jpeg2000", diff --git a/libavcodec/libdavs2.c b/libavcodec/libdavs2.c new file mode 100644 index 0000000..3537f40 --- /dev/null +++ b/libavcodec/libdavs2.c @@ -0,0 +1,216 @@ +/* + * AVS2 decoding using the davs2 library + * + * Copyright (C) 2018 Yiqun Xu, <yiqun...@vipl.ict.ac.cn> + * Falei Luo, <falei....@gmail.com> + * Huiwen Ren, <hwr...@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 "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/avutil.h" +#include "avcodec.h" +#include "libavutil/imgutils.h" +#include "internal.h" + +#include <stdio.h> +#include <stdlib.h> +#include <davs2.h> + +typedef struct DAVS2Context { + AVCodecContext *avctx; + void *dec_handle; + int got_seqhdr; + + void *decoder; + + AVFrame *frame; + davs2_param_t param; // decoding parameters + davs2_packet_t packet; // input bitstream + int ret; + + int img_width[3]; + int img_height[3]; + int out_flag; + int decoded_frames; + + davs2_picture_t out_frame; // output data, frame data + davs2_seq_info_t headerset; // output data, sequence header + +}DAVS2Context; + +static int ff_davs2_init(AVCodecContext *avctx) +{ + DAVS2Context *cad = avctx->priv_data; + + /* init the decoder */ + cad->param.threads = 0; + cad->param.i_info_level = 0; + cad->decoder = davs2_decoder_open(&cad->param); + avctx->flags |= AV_CODEC_FLAG_TRUNCATED; + + av_log(avctx, AV_LOG_WARNING, "[davs2] decoder created. 0x%llx\n", cad->decoder); + return 0; +} + +/* --------------------------------------------------------------------------- + */ +static int DumpFrames(AVCodecContext *avctx, davs2_picture_t *pic, davs2_seq_info_t *headerset, AVFrame *frm) +{ + DAVS2Context *cad = avctx->priv_data; + avctx->flags |= AV_CODEC_FLAG_TRUNCATED; + + if (headerset == NULL) { + return 0; + } + + if (pic == NULL || pic->ret_type == DAVS2_GOT_HEADER) { + avctx->frame_size = (headerset->horizontal_size * headerset->vertical_size * 3 * headerset->bytes_per_sample) >> 1; + avctx->coded_width = headerset->horizontal_size; + avctx->coded_height = headerset->vertical_size; + avctx->width = headerset->horizontal_size; + avctx->height = headerset->vertical_size; + avctx->pix_fmt = (headerset->output_bitdepth == 10 ? AV_PIX_FMT_YUV420P10 : AV_PIX_FMT_YUV420P); + avctx->framerate.num = (int)(headerset->frame_rate); + avctx->framerate.den = 1; + return 0; + } + + const int bytes_per_sample = pic->bytes_per_sample; + int i; + + for (i = 0; i < 3; ++i) { + int size_plane = pic->width[i] * pic->lines[i] * bytes_per_sample; + frm->buf[i] = av_buffer_alloc(size_plane); + frm->data[i] = frm->buf[i]->data; + frm->linesize[i] = pic->width[i] * bytes_per_sample; + memcpy(frm->data[i], pic->planes[i], size_plane); + } + + frm->width = cad->headerset.horizontal_size; + frm->height = cad->headerset.vertical_size; + frm->pts = cad->out_frame.pts; + + frm->key_frame = 1; + frm->pict_type = AV_PICTURE_TYPE_I; + frm->format = avctx->pix_fmt; + cad->out_flag = 1; + + cad->decoded_frames++; + return 1; +} + +static int ff_davs2_end(AVCodecContext *avctx) +{ + DAVS2Context *cad = avctx->priv_data; + + /* close the decoder */ + if (cad->decoder != NULL) { + davs2_decoder_close(cad->decoder); + av_log(avctx, AV_LOG_WARNING, "[davs2] decoder destroyed. 0x%llx; frames %d\n", cad->decoder, cad->decoded_frames); + cad->decoder = NULL; + } + + return 0; +} + +static int davs2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) +{ + DAVS2Context *cad = avctx->priv_data; + int buf_size = avpkt->size; + const uint8_t *buf_ptr = avpkt->data; + AVFrame *frm = data; + + *got_frame = 0; + cad->out_flag=0; + cad->frame = frm; + avctx->flags |= AV_CODEC_FLAG_TRUNCATED; + + if (buf_size == 0) { + cad->packet.data = buf_ptr; + cad->packet.len = buf_size; + cad->packet.pts = avpkt->pts; + cad->packet.dts = avpkt->dts; + + for (;;) { + cad->ret = davs2_decoder_flush(cad->decoder, &cad->headerset, &cad->out_frame); + + if (cad->ret < 0) { + return 0; + } + + if (cad->out_frame.ret_type != DAVS2_DEFAULT) { + *got_frame = DumpFrames(avctx, &cad->out_frame, &cad->headerset, frm); + davs2_decoder_frame_unref(cad->decoder, &cad->out_frame); + } + if(cad->out_flag == 1) { + break; + } + } + return 0; + } else { + for(; buf_size > 0;) { + int len = buf_size; // for API-3, pass all data in + + cad->packet.marker = 0; + cad->packet.data = buf_ptr; + cad->packet.len = len; + cad->packet.pts = avpkt->pts; + cad->packet.dts = avpkt->dts; + + len = davs2_decoder_decode(cad->decoder, &cad->packet, &cad->headerset, &cad->out_frame); + + if (cad->out_frame.ret_type != DAVS2_DEFAULT) { + *got_frame = DumpFrames(avctx, &cad->out_frame, &cad->headerset, frm); + davs2_decoder_frame_unref(cad->decoder, &cad->out_frame); + } + + if (len < 0) { + av_log(NULL, AV_LOG_ERROR, "An decoder error counted\n"); + + return -1; + } + + buf_ptr += len; + buf_size -= len; + + if(cad->out_flag == 1) { + break; + } + } + } + + buf_size = (buf_ptr - avpkt->data); + + return buf_size; +} + +AVCodec ff_libdavs2_decoder = { + .name = "libdavs2", + .long_name = NULL_IF_CONFIG_SMALL("Decoder for Chinese AVS2"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_AVS2, + .priv_data_size = sizeof(DAVS2Context), + .init = ff_davs2_init, + .close = ff_davs2_end, + .decode = davs2_decode_frame, + .capabilities = AV_CODEC_CAP_DELAY,//AV_CODEC_CAP_DR1 | + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_NONE }, +}; diff --git a/libavformat/riff.c b/libavformat/riff.c index 8911725..4153372 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -369,6 +369,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_ZMBV, MKTAG('Z', 'M', 'B', 'V') }, { AV_CODEC_ID_KMVC, MKTAG('K', 'M', 'V', 'C') }, { AV_CODEC_ID_CAVS, MKTAG('C', 'A', 'V', 'S') }, + { AV_CODEC_ID_AVS2, MKTAG('A', 'V', 'S', '2') }, { AV_CODEC_ID_JPEG2000, MKTAG('m', 'j', 'p', '2') }, { AV_CODEC_ID_JPEG2000, MKTAG('M', 'J', '2', 'C') }, { AV_CODEC_ID_JPEG2000, MKTAG('L', 'J', '2', 'C') }, -- 2.7.4 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel