diff --git a/mxVision/Ascendffmpeg/doc/examples/filtering_video.c b/mxVision/Ascendffmpeg/doc/examples/filtering_video.c index 105a200d93401f6ea27cd0b8cb71fca8b3ff4b98..a98b9622a406c9a46c12369d6ed3948e8733bca2 100644 --- a/mxVision/Ascendffmpeg/doc/examples/filtering_video.c +++ b/mxVision/Ascendffmpeg/doc/examples/filtering_video.c @@ -61,6 +61,7 @@ static int open_input_file(const char *filename) return ret; } + av_log(NULL, AV_LOG_ERROR, "filtering_video.c: Cannot find stream information\n"); if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); return ret; diff --git a/mxVision/Ascendffmpeg/fftools/ffmpeg_opt.c b/mxVision/Ascendffmpeg/fftools/ffmpeg_opt.c index c2386e4a38477c36f741f417ea410078b421d3a3..f0b0efce577cf53bb819855bd3e81e2e7110872a 100644 --- a/mxVision/Ascendffmpeg/fftools/ffmpeg_opt.c +++ b/mxVision/Ascendffmpeg/fftools/ffmpeg_opt.c @@ -1194,6 +1194,7 @@ static int open_input_file(OptionsContext *o, const char *filename) /* If not enough info to get the stream parameters, we decode the first frames to get it. (used in mpeg case for example) */ + av_log(NULL, AV_LOG_WARNING, "ffmpeg_opt.c: Cannot find stream information\n"); ret = avformat_find_stream_info(ic, opts); for (i = 0; i < orig_nb_streams; i++) diff --git a/mxVision/Ascendffmpeg/libavcodec/Makefile b/mxVision/Ascendffmpeg/libavcodec/Makefile index fc092e39fe121707c941f5d5b265c3192cc07936..e903ae2127523337ab802d7af6bea0be189aa3c5 100644 --- a/mxVision/Ascendffmpeg/libavcodec/Makefile +++ b/mxVision/Ascendffmpeg/libavcodec/Makefile @@ -27,6 +27,8 @@ HEADERS = ac3_parser.h \ xvmc.h \ ascend_dec.h \ ascend_enc.h \ + ascend_jpeg_dec.h \ + ascend_dec_mjpeg.h \ OBJS = ac3_parser.o \ adts_parser.o \ @@ -374,6 +376,8 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \ h264_slice.o h264data.o OBJS-$(CONFIG_H264_ASCEND_DECODER) += ascend_dec.o OBJS-$(CONFIG_H264_ASCEND_ENCODER) += ascend_enc.o +OBJS-$(CONFIG_JPEG_ASCEND_DECODER) += ascend_jpeg_dec.o +OBJS-$(CONFIG_MJPEG_ASCEND_HWACCEL) += ascend_dec_mjpeg.o OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o diff --git a/mxVision/Ascendffmpeg/libavcodec/allcodecs.c b/mxVision/Ascendffmpeg/libavcodec/allcodecs.c index b6885f8cda7a1017dbbc1c32221204af2ec7da46..3bbbcf8520cfa7bb32340eec7be26def8a6ec9c3 100644 --- a/mxVision/Ascendffmpeg/libavcodec/allcodecs.c +++ b/mxVision/Ascendffmpeg/libavcodec/allcodecs.c @@ -791,6 +791,8 @@ extern AVCodec ff_h264_ascend_decoder; extern AVCodec ff_h265_ascend_decoder; extern AVCodec ff_h264_ascend_encoder; extern AVCodec ff_h265_ascend_encoder; +extern AVCodec ff_jpeg_ascend_decoder; +extern AVCodec ff_ascend_mjpeg_decoder; extern AVCodec ff_h264_amf_encoder; extern AVCodec ff_h264_cuvid_decoder; extern AVCodec ff_h264_mf_encoder; diff --git a/mxVision/Ascendffmpeg/libavcodec/ascend_dec.c b/mxVision/Ascendffmpeg/libavcodec/ascend_dec.c index 1705252faae1f92b666ecdd7a79cb8c9ab90d870..7dfc65a19056bdafa33897d25abdb4b0bdbb06da 100644 --- a/mxVision/Ascendffmpeg/libavcodec/ascend_dec.c +++ b/mxVision/Ascendffmpeg/libavcodec/ascend_dec.c @@ -542,6 +542,7 @@ static av_cold int ff_himpi_decode_init(AVCodecContext *avctx) enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_ASCEND, AV_PIX_FMT_NV12, AV_PIX_FMT_NONE }; avctx->pix_fmt = ff_get_format(avctx, pix_fmts); + av_log(avctx, AV_LOG_ERROR, "Error, ff_get_format failed with format id: %d.\n", avctx->pix_fmt); if (avctx->pix_fmt < 0) { av_log(avctx, AV_LOG_ERROR, "Error, ff_get_format failed with format id: %d.\n", avctx->pix_fmt); return AVERROR_BUG; diff --git a/mxVision/Ascendffmpeg/libavcodec/ascend_dec_mjpeg.c b/mxVision/Ascendffmpeg/libavcodec/ascend_dec_mjpeg.c new file mode 100644 index 0000000000000000000000000000000000000000..99827ebaf25c8a610854917d6715c4d0d3ac635e --- /dev/null +++ b/mxVision/Ascendffmpeg/libavcodec/ascend_dec_mjpeg.c @@ -0,0 +1,506 @@ +/* + * Copyright(c) 2024. Huawei Technologies Co.,Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except int compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "libavutil/imgutils.h" +#include "libavutil/avassert.h" +#include "libavutil/opt.h" +#include "avcodec.h" +#include "blockdsp.h" +#include "copy_block.h" +#include "decode.h" +#include "hwconfig.h" +#include "idctdsp.h" +#include "internal.h" +#include "jpegtables.h" +#include "mjpeg.h" +#include "mjpegdec.h" +#include "jpeglsdec.h" +#include "profiles.h" +#include "put_bits.h" +#include "tiff.h" +#include "exif.h" +#include "bytestream.h" + +static AVBufferRef *hw_device_ref = NULL; + +static const uint8_t jpeg_header2[] = { + 0xff, 0xd8, // SOI + 0xff, 0xe0, // APP0 + 0x00, 0x10, // APP0 header size + 0x4a, 0x46, 0x49, 0x46, 0x00, // ID string 'JFIF\0' + 0x01, 0x01, // version + 0x00, // bits per type + 0x00, 0x00, // X density + 0x00, 0x00, // Y density + 0x00, // X thumbnail size + 0x00, // Y thumbnail size +}; + +static const int dht_segment_size2 = 420; + +static const uint8_t dht_segment_head2[] = {0xFF, 0xC4, 0x01, 0xA2, 0x00}; +static const uint8_t dht_segment_frag2[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static uint8_t *append2(uint8_t *buf, const uint8_t *src, int size) +{ + memcpy(buf, src, size); + return buf + size; +} + +static uint8_t *append_dht_segment2(uint8_t *buf) +{ + buf = append2(buf, dht_segment_head2, sizeof(dht_segment_head2)); + buf = append2(buf, avpriv_mjpeg_bits_dc_luminance + 1, 16); + buf = append2(buf, dht_segment_frag2, sizeof(dht_segment_frag2)); + buf = append2(buf, avpriv_mjpeg_val_dc, 12); + *(buf++) = 0x10; + buf = append2(buf, avpriv_mjpeg_bits_ac_luminance + 1, 16); + buf = append2(buf, avpriv_mjpeg_val_ac_luminance, 162); + *(buf++) = 0x11; + buf = append2(buf, avpriv_mjpeg_bits_ac_chrominance + 1, 16); + buf = append2(buf, avpriv_mjpeg_val_ac_chrominance, 162); + return buf; +} + +#define REF_FRAME_NUM 8 +#define DISPLAY_FRAME_NUM 2 +#define FFALIGNMJPEG(x, a) (((x) + (a) - 1) &~ ((a) - 1)) +#define WIDTH_ALIGN 2 +#define HEIGHT_ALIGN 16 + +av_cold int ff_mjpeg_ascend_decode_init(AvCodecContext* avctx) +{ + AscendMjpegDecodeContext *s = avctx->priv_data; + int ret; + + enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_ASCEND, AV_PIX_FMT_NV12, AV_PIX_FMT_NONE }; + avctx->pix_fmt = ff_get_format(avctx, pix_fmts); + if (avctx->pix_fmt != AV_PIX_FMT_ASCEND) { + av_log(avctx, AV_LOG_ERROR, "Perhaps the command \"-hwaccel ascend\" is missing. Please check it.\n"); + return AVERROR(EINVAL); + } + + if (avctx->width < 128 || avctx->height < 128 || avctx->width > 4096 || avctx->height > 4096) { + av_log(avctx, AV_LOG_ERROR, "MJPEG decoder only support resolution: 128x128 ~ 4096x4096, now: %dx%d.\n", avctx->width, avctx->height); + return AVERROR(EINVAL); + } + + char device_id[sizeof(int)]; + sprintf(device_id, "%d", s->device_id); + + AVASCENDDeviceContext* hw_device_ctx; + AVHWFramesContext* hw_frame_ctx; + if (avctx->hw_frame_ctx) { + av_buffer_unref(&s->hw_frame_ref); + s->hw_frame_ref = av_buffer_ref(avctx->hw_frame_ctx); + if (!s->hw_frame_ref) { + ret = AVERROR(EINVAL); + goto #error; + } + + hw_frame_ctx = (AVHWFramesContext*)s->hw_frame_ref->data; + if (!hw_frame_ctx->pool || (avctx->width != hw_frame_ctx->width)) { + if (hw_frame_ctx->pool) { + av_buffer_pool_uninit(&hw_frame_ctx->pool); + } + hw_frame_ctx->width = avctx->width; + hw_frame_ctx->height = avctx->height; + hw_frame_ctx->initial_pool_size = 2; + hw_frame_ctx->format = AV_PIX_FMT_ASCEND; + hw_frame_ctx->sw_format = AV_PIX_FMT_NV12; + } + ret = av_hwframe_ctx_init(s->hw_frame_ref); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "HWFrame context init failed, ret is %d.\n", ret); + return AVERROR(ENAVAIL); + } + + s->hw_device_ref = av_buffer_ref(hw_frame_ctx->device_ref); + if (!s->hw_device_ref) { + av_log(avctx, AV_LOG_ERROR, "Get hw_device_ref failed.\n"); + ret = AVERROR(EINVAL); + goto error; + } + } else { + if (avctx->hw_device_ctx) { + s->hw_device_ref = av_buffer_ref(avctx->hw_device_ctx); + if (!s->hw_device_ref) { + av_log(avctx, AV_LOG_ERROR, "ref hwdevice failed.\n"); + ret = AVERROR(EINVAL); + goto error; + } + } else { + ret = av_hwdevice_ctx_create(&s->hw_device_ref, AV_HWDEVICE_TYPE_ASCEND, device_id, NULL, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "hwdevice context create failed.\n"); + goto error; + } + } + s->hw_frame_ref = av_hwframe_ctx_alloc(s->hw_device_ref); + if (!s->hw_frame_ref) { + av_log(avctx, AV_LOG_ERROR, "hwframe ctx alloc falied.\n"); + ret = AVERROR(EINVAL); + goto error; + } + hw_frame_ctx = (AVHWFramesContext*)s->hw_frame_ref->data; + if (!hw_frame_ctx->pool) { + hw_frame_ctx->width = avctx_width; + hw_frame_ctx->height = avctx->height; + hw_frame_ctx->initial_pool_size = 2; + hw_frame_ctx->format = AV_PIX_FMT_ASCEND; + hw_frame_ctx->sw_format = AV_PIX_FMT_NV12; + ret = av_hwframe_ctx_init(s->hw_frame_ref); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "hwframe ctx init error, ret is %d.\n", ret); + ret = AVERROR(EINVAL); + goto error; + } + } + } + + hw_device_ctx = ((AVHWDeviceContext*)s->hw_device_ref->data)->hwctx; + s->hw_device_ctx = hw_device_ctx; + s->hw_frame_ctx = hw_frame_ctx; + s->ascend_ctx = s->hw_device_ctx->ascend_ctx; + + ret = aclrtSetCurrentContext(s->ascend_ctx->context); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Set context failed at line(%d) in func(%s), ret is %d.\n", __LINE__, __func__, ret); + return ret; + } + + ret = hi_mpi_sys_init(); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi sys init failed, ret is %d.\n", ret); + return ret; + } + + hi_vdec_chn_attr chn_attr_; + chn_attr_.type = HI_PT_JPEG; + chn_attr_.mode = HI_VDEC_SEND_MODE_FRAME; + chn_attr_.pic_width = 1920; + chn_attr_.pic_height = 1080; + chn_attr_.stream_buf_size = chn_attr_.pic_width * chn_attr_.height * 3 / 2; + chn_attr_.frame_buf_cnt = REF_FRAME_NUM + DISPLAY_FRAME_NUM + 1; + + hi_pic_buf_attr buf_attr_; + buf_attr_.width = chn_attr_.pic_width; + buf_attr_.height = chn_attr_.pic_height; + buf_attr_.align = 0; + buf_attr_.bit_width = HI_DATA_BIT_WIDTH_8; + buf_attr_.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; + buf_attr_.compress_mode = HI_COMPRESS_MODE_NONE; + + chn_attr_.frame_buf_size = hi_vdec_get_pic_buf_size(chn_attr_.type, &buf_attr_); + chn_attr_.video_attr.ref_frame_num = REF_FRAME_NUM; + chn_attr_.video_attr.temporal_mvp_en = HI_TRUE; + chn_attr_.video_attr.tmv_buf_size = hi_vdec_get_tmv_buf_size(chn_attr_.type, + chn_attr_.pic_width, + chn_attr_.pic_height); + s->channel_id = 0; + uint32_t channel_id = s->channel_id; + ret = hi_mpi_vdec_create_chn(channel_id, &chn_attr_); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi create vdec channel failed, ret is %d.\n", ret); + return ret; + } + + hi_vdec_chn_param chn_param_; + ret = hi_mpi_vdec_get_chn_param(channel_id, &chn_param_); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi vdec get channel param failed, ret is %d.\n", ret); + return ret; + } + + chn_param_.video_param.dec_mode = HI_VIDEO_DEC_MODE_IPB; + chn_param_.video_param.compress_mode = HI_COMPRESS_MODE_HFBC; + chn_param_.video_param.video_format = HI_VIDEO_FORMAT_TILE_64x16; + chn_param_.display_frame_num = DISPLAY_FRAME_NUM; + chn_param_.video_param.out_order = HI_VIDEO_OUT_ORDER_DISPLAY; + + ret = hi_mpi_vdec_set_chn_param(channel_id, &chn_param_); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi vdec set channel param failed, ret is %d.\n", ret); + return ret; + } + + ret = hi_mpi_vdec_start_recv_stream(channel_id); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi vdec start receive stream failed, ret is %d.\n", ret); + return ret; + } + + s->pkt = av_packet_alloc(); + if (!s->pkt) + return AVERROR(ENOMEM); + s->avctx = avctx; + return 0; +} + +int ff_mjpeg_receive_frame(AvCodecContext* avctx, AVFrame* frame) +{ + AscendMjpegDecodeContext *s = avctx->priv_data; + int ret = 0; + ret = mjpeg_get_packet(avctx); + if (ret < 0) { + return ret; + } + + /* GET JPEG */ + AVPacket *out = av_packet_alloc(); + uint8_t* output; + int input_skip, output_size; + AVPacket *in = s->pkt; + + if (in->size < 12) { + av_log(avctx, AV_LOG_ERROR, "Input is truncate.\n"); + return AVERROR_INVALIDDATA; + } + + if (AV_RB16(int->data) != 0xffd8) { + av_log(avctx, AV_LOG_ERROR, "Input is not MJPEG.\n"); + return AVERROR_INVALIDDATA; + } + + if (in->data[2] == 0xff && in->data[3] == APP) { + input_skip = (in->data[4] << 8) + in->data[5] + 4; + } else { + input_skip = 2; + } + + if (in->size < input_skip) { + av_log(avctx, AV_LOG_ERROR, "Input is truncate.\n"); + return AVERROR_INVALIDDATA; + } + + output_size = in->size - input_skip + sizeof(jpeg_header2) + dht_segment_size2; + ret = av_new_packet(out, output_size); + if (ret < 0) + return AVERROR_INVALIDDATA; + output = out->data; + output = append2(output, jpeg_header2, sizeof(jpeg_header2)); + output = append_dht_segment2(output); + output = append2(output, in->data + input_skip, in->size - input_skip); + + /* JPEG to YUV420 By Ascend */ + ret = aclrtSetCurrentContext(s->ascend_ctx->context); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Set context failed, ret is %d.\n", ret); + return ret; + } + + uint8_t* streamBuffer = NULL; + int device_id = 0; + ret = hi_mpi_dvpp_malloc(device_id, &streamBuffer, output_size); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi malloc packet failed, ret is %d.\n", ret); + return ret; + } + + ret = aclrtMemcpy(streamBuffer, output_size, output_size, out->data, output_size, ACL_MEMCPY_HOST_TO_DEVICE); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Mem copy H2D failed. ret is %d.\n", ret); + return ret; + } + + hi_vdec_stream stream; + stream.pts = 0; + stream.addr = streamBuffer; + stream.len = output_size; + stream.end_of_frame = HI_TRUE; + stream.end_of_stream = HI_FALSE; + stream.need_display = HI_TRUE; + + hi_vdec_pic_info pic_info; + pic_info.width = s->avctx->width; + pic_info.height = s->avctx->height; + pic_info.width_stride = FFALIGNMJPEG(pic_info.width, WIDTH_ALIGN); + pic_info.height_stride = FFALIGNMJPEG(pic_info.height, HEIGHT_ALIGN); + pic_info.offset_top = 0; + pic_info.offset_bottom = 0; + pic_info.offset_left = 0; + pic_info.offset_right = 0; + + uint32_t size = pic_info.width_stride * pic_info.height_stride * 3 / 2; + pic_info.buffer_size = size; + pic_info.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; + + void* picBuffer = NULL; + ret = hi_mpi_dvpp_malloc(device_id, &picBuffer, size); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi malloc falied, ret is %d.\n", ret); + return ret; + } + + pic_info.vir_addr = (uint64_t)picBuffer; + + ret = hi_mpi_vdec_send_stream(s->channel_id, &stream, &pic_info, 1000); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Send stream failed, ret is %d.\n", ret); + return ret; + } + + hi_video_frame_info got_frame; + hi_vdec_stream got_stream; + hi_vdec_supplement_info stSupplement; + ret = hi_mpi_vdec_get_frame(s->channel_id, &got_frame, &stSupplement, &got_stream, 100); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Get frame failed, ret is %d.\n", ret); + return ret; + } + size_t decResult = got_frame.v_frame.frame_flag; + hi_mpi_dvpp_free(got_stream.addr); + if (decResult != 0 && got_frame.v_frame.virt_addr[0] != NULL) { + hi_mpi_dvpp_free(got_frame.v_frame.virt_addr[0]); + return ret; + } + if (decResult != 0 || got_frame.v_frame.virt_addr[0] == NULL || got_stream.need_display = HI_FALSE) { + ret = hi_mpi_vdec_release_frame(s->channel_id, &got_frame); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi release frame failed, ret is %d.\n", ret); + return ret; + } + return -1; + } + ret = hi_mpi_vdec_release_frame(s->channel_id, &got_frame); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi release frame failed, ret is %d.\n", ret); + return ret; + } + + avctx->pix_fmt = (int)AV_PIX_FMT_NV12; + ret = av_hwframe_get_buffer(s->hw_frame_ref, frame, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Frame get buffer failed, ret is %d.\n", ret); + return AVERROR(EINVAL); + } + ret = ff_deocde_frame_props(avctx, frame); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "") + } + + frame->pkt_pos = -1; + frame->pkt_duration = 0; + frame->pkt_size = -1; + frame->pts = got_frame.v_frame.pts; + frame->pkt_pts = frame->pts; + frame->pkt_dts = out->dts; + + uint32_t offset = 0; + for (int i = 0; i < 2; i++) { + size_t dstBytes = got_frame.v_frame.width_stride[0] * got_frame.v_frame.height_stride[0] * (i ? 1.0 / 2 : 1); + ret = aclrtMemcpy(frame->data[i], dstBytes, got_frame.v_frame.virt_addr[0] + offset, dstBytes, + ACL_MEMCPY_DEVICE_TO_DEVICE); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Mem copy D2D failed, ret is %d.\n", ret); + hi_mpi_dvpp_free(got_frame.v_frame.virt_addr[0]); + return ret; + } + offset += dstBytes; + } + hi_mpi_dvpp_free(got_frame.v_frame.virt_addr[0]); + av_packet_free(&out); + return ret; +} + +av_cold int ff_mjpeg_decode_end(AvCodecContext* avctx) +{ + AscendMjpegDecodeContext *s = avctx->priv_data; + int i, j, ret; + ret = aclrtSetCurrentContext(s->ascend_ctx->context); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Set context failed, ret is %d.\n", ret); + return ret; + } + + ret = hi_mpi_vdec_stop_recv_stream(s->channel_id); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi stop receive stream failed, ret is %d.\n", ret); + return ret; + } + + ret = hi_mpi_vdec_destroy_chn(s->channel_id); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi destroy channel failed, ret is %d.\n", ret); + return ret; + } + + ret = hi_mpi_sys_exit(); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi sys exit failed, ret is %d.\n", ret); + return ret; + } + + av_buffer_unref(&s->hw_device_ref); + return 0; +} + +static void ascend_decode_flush(AvCodecContext* avctx) +{ + ff_mjpeg_decode_end(avctx); + ff_mjpeg_decode_init(avctx); +} + +#if CONFIG_MJPEG_ASCEND_HWACCEL + +#define OFFSET(x) offsetof(AscendMjpegDecodeContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static_cast const AVOption options[] = { + { "device_id", "Use to choose the ascend chip.", OFFSET(device_id), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 8, VD }, + { "channel_id", "Set channelId of decoder.", OFFSET(channel_id), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 255, VD }, + { NULL } +}; + +static const AVClass mjpegdec_class = { + .class_name = "Ascend MJPEG decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVCodecHWConfigInternal* ascend_hw_config2[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_ASCEND, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | + AV_CODEC_HW_CONFIG_METHOD_INTERNAL, + .device_type = AV_HWDEVICE_TYPE_ASCEND + }, + .hwaccel = NULL, + }, + NULL +}; + +AVCodec ff_ascend_mjpeg_decoder = { + .name = "mjpeg_ascend_dec", + .long_name = NULL_IF_CONFIG_SMALL("Ascend MJPEG (MOTION JPEG)"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MJPEG, + .priv_data_size = sizeof(AscendMjpegDecodeContext), + .init = ff_mjpeg_ascend_decode_init, + .close = ff_mjpeg_ascend_decode_end, + .receive_frame = ff_mjpeg_ascend_receive_frame, + .flush = ascend_decode_flush, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, + .priv_class = &mjpegdec_class, + .hw_configs = ascend_hw_config2, +}; + +##endif \ No newline at end of file diff --git a/mxVision/Ascendffmpeg/libavcodec/ascend_dec_mjpeg.h b/mxVision/Ascendffmpeg/libavcodec/ascend_dec_mjpeg.h new file mode 100644 index 0000000000000000000000000000000000000000..f269c876d9ae6436e260f84d4b6e8fc0f972a0e2 --- /dev/null +++ b/mxVision/Ascendffmpeg/libavcodec/ascend_dec_mjpeg.h @@ -0,0 +1,68 @@ +/* + * MJPEG decoder + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2003 Alex Beregszaszi + * Copyright (c) 2003-2004 Michael Niedermayer + * + * 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 + */ + +/** + * @file + * MJPEG decoder. + */ + +#ifndef ASCEND_AVCODEC_MJPEGDEC_H +#define ASCEND_AVCODEC_MJPEGDEC_H + +#include "libavutil/log.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" +#include "libavutil/stereo3d.h" + +#include "avcodec.h" +#include "blockdsp.h" +#include "get_bits.h" +#include "hpeldsp.h" +#include "idctdsp.h" + +#undef near /* This file uses struct member 'near' which in windows.h is defined as empty. */ + +typedef struct AscendMJpegDecodeContext { + AVClass *class; + AVCodecContext *avctx; + int buf_size; + + AVPacket *pkt; + enum AVPixelFormat hwaccel_sw_pix_fmt; + enum AVPixelFormat hwaccel_pix_fmt; + void* hwaccel_picture_private; + int device_id; + uint32_t channel_id; + uint32_t vdec_width; + uint32_t vdec_height; + AVBufferRef* hw_device_ref; + AVBufferRef* hw_frame_ref; + AVHWFramesContext* hw_frames_ctx; + AscendContext* ascend_ctx; +} AscendMJpegDecodeContext; + +int ff_mjpeg_ascend_decode_init(AVCodecContext *avctx); +int ff_mjpeg_ascend_decode_end(AVCodecContext *avctx); +int ff_mjpeg_ascend_receive_frame(AVCodecContext *avctx, AVFrame *frame); + +#endif diff --git a/mxVision/Ascendffmpeg/libavcodec/ascend_jpeg_dec.c b/mxVision/Ascendffmpeg/libavcodec/ascend_jpeg_dec.c new file mode 100644 index 0000000000000000000000000000000000000000..a9ca3aee18225e8322ad706ee7415c3b2036d4ce --- /dev/null +++ b/mxVision/Ascendffmpeg/libavcodec/ascend_jpeg_dec.c @@ -0,0 +1,1076 @@ +/* + * Copyright(c) 2020. Huawei Technologies Co.,Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except int compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "ascend_jpeg_dec.h" + +//static void *get_frame(void *arg) +//{ +// ASCENDContext_t *ctx = (ASCENDContext_t*)arg; +// int ret = 0; +// int eos_flag = 0; +// ret = aclrtSetCurrentContext(ctx->ascend_ctx->context); +// if (ret != 0) { +// av_log(ctx, AV_LOG_ERROR, "Set context failed, ret is %d.\n", ret); +// return ((void*) (-1)); +// } +// +// hi_video_frame_info frame; +// hi_vdec_stream stream; +// hi_vdec_supplement_info stSupplement; +// +// av_log(NULL, AV_LOG_INFO, "Thread start.\n"); +// +// while (ctx->thread_run_flag) { +// ret = hi_mpi_vdec_get_frame(ctx->channel_id, &frame, &stSupplement, &stream, VDEC_GET_TIME_OUT); +// if (ret != 0) { +// if (ctx->decoder_flushing && ret == HI_ERR_VDEC_BUF_EMPTY) { +// eos_flag = 1; +// av_log(ctx, AV_LOG_DEBUG, "Decoder flushing or stream eos.\n"); +// } else { +// av_log(ctx, AV_LOG_DEBUG, "HiMpi get frame failed, ret is %d.\n", ret); +// continue; +// } +// } +// +// size_t decResult = frame.v_frame.frame_flag; +// if (eos_flag) { +// // eos +// FrameInfo_t frame_info; +// memset(&frame_info, 0, sizeof(FrameInfo_t)); +// frame_info.event_type = EVENT_EOS; +// +// ff_mutex_lock(&ctx->queue_mutex); +// av_fifo_generic_write(ctx->frame_queue, &frame_info, sizeof(FrameInfo_t), NULL); +// ff_mutex_unlock(&ctx->queue_mutex); +// sem_post(&ctx->eos_sema); +// av_log(ctx, AV_LOG_DEBUG, "Decode got eos.\n"); +// break; +// } +// +// hi_mpi_dvpp_free(stream.addr); +// if (ret != 0) { +// av_log(ctx, AV_LOG_ERROR, "HiMpi free stream failed, ret is %d.\n", ret); +// } +// if (decResult != 0 && frame.v_frame.virt_addr[0] != NULL) { +// hi_mpi_dvpp_free(frame.v_frame.virt_addr[0]); +// } +// +// if (decResult != 0 || frame.v_frame.virt_addr[0] == NULL || stream.need_display == HI_FALSE) { +// ret = hi_mpi_vdec_release_frame(ctx->channel_id, &frame); +// if (ret != 0) { +// av_log(ctx, AV_LOG_ERROR, "HiMpi release frame failed, ret is %d.", ret); +// return ((void*) (-1)); +// } +// continue; +// } +// FrameInfo_t frame_info; +// frame_info.ascend_ctx = ctx; +// get_vdec_frame_info(&frame_info, frame); +// +// ff_mutex_lock(&ctx->queue_mutex); +// av_fifo_generic_read(ctx->dts_queue, &frame_info.dts, sizeof(int64_t), NULL); +// av_fifo_generic_write(ctx->frame_queue, &frame_info, sizeof(FrameInfo_t), NULL); +// ff_mutex_unlock(&ctx->queue_mutex); +// +// ret = hi_mpi_vdec_release_frame(ctx->channel_id, &frame); +// if (ret != 0) { +// av_log(ctx, AV_LOG_ERROR, "HiMpi release frame failed, ret is %d.\n", ret); +// return ((void*) (-1)); +// } +// +// ctx->total_out_frame_count++; +// } +// return NULL; +//} + +static inline int decode_params_checking(AVCodecContext* avctx) +{ + switch (avctx->codec->id) { + case AV_CODEC_ID_JPEG2000: + if (avctx->width < 128 || avctx->height < 128 || + avctx->width > 4096 || avctx->height > 4096) { + av_log(avctx, AV_LOG_ERROR, + "H264 decoder only support resolution: 128x128 ~ 4096x4096, now: %dx%d.\n", + avctx->width, avctx->height); + return -1; + } + break; + + default: + break; + } + + return 0; +} + +static av_cold int ff_himpi_decode_end(AVCodecContext *avctx) +{ + av_log(avctx, AV_LOG_ERROR, "here is decode end 0.\n"); + ASCENDContext_t *ctx = (ASCENDContext_t*)avctx->priv_data; + int ret = 0; + int semvalue = 0; + struct timespec ts; + if (ctx == NULL || avctx->priv_data == NULL) { + av_log(ctx, AV_LOG_ERROR, "HiMpi decode end error, AVCodecContext is NULL.\n"); + return AVERROR_BUG; + } + + ret = aclrtSetCurrentContext(ctx->ascend_ctx->context); + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "Set Context failed, ret is %d.\n", ret); + return ret; + } + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 3; + if (sem_timedwait(&(ctx->eos_sema), &ts) == -1) { + semvalue = -1; + sem_getvalue(&ctx->eos_sema, &semvalue); + av_log(ctx, AV_LOG_ERROR, "Decode sem_timewait = -1, semvalue = %d.\n", semvalue); + } + + if (ctx->hi_mpi_init_flag) { + ret = hi_mpi_vdec_stop_recv_stream(ctx->channel_id); + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "HiMpi stop receive stream failed, ret is %d.\n", ret); + return ret; + } + + ret = hi_mpi_vdec_destroy_chn(ctx->channel_id); + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "HiMpi destroy channel failed, ret is %d.\n", ret); + return ret; + } + + ret = hi_mpi_sys_exit(); + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "HiMpi sys exit failed, ret is %d.\n", ret); + return ret; + } + } + + ctx->hi_mpi_init_flag = 0; + ctx->decode_run_flag = 0; + +// if (ctx->thread_run_flag) { +// ctx->thread_run_flag = 0; +// pthread_join(ctx->thread_id, NULL); +// } + + sem_destroy(&ctx->eos_sema); + + if (ctx->frame_queue) { + av_fifo_freep(&ctx->frame_queue); + ctx->frame_queue = NULL; + } + + ff_mutex_destroy(&ctx->queue_mutex); + if (ctx->bsf) { + av_bsf_free(&ctx->bsf); + ctx->bsf = NULL; + } + + av_buffer_unref(&ctx->hw_frame_ref); + av_buffer_unref(&ctx->hw_device_ref); + + av_log(avctx, AV_LOG_INFO, "Decode hw send packet count is: %llu.\n", ctx->total_out_frame_count); + av_log(avctx, AV_LOG_INFO, "Decode hw out frame count is: %llu.\n", ctx->total_packet_count); + return 0; +} + +static int malloc_and_send_frame(AVCodecContext *avctx, const AVPacket *avpkt) +{ + ASCENDContext_t *ctx = (ASCENDContext_t*)avctx->priv_data; + av_log(avctx, AV_LOG_ERROR, "extradata_size is %d.\n", avctx->extradata_size); + int ret = 0; +// if (ctx->first_packet) { +// if (avctx->extradata_size) { +// uint8_t* streamBuffer = NULL; +// ret = hi_mpi_dvpp_malloc(ctx->device_id, &streamBuffer, avctx->extradata_size); +// if (ret != 0) { +// av_log(avctx, AV_LOG_ERROR, "HiMpi malloc first packet failed, ret is %d.\n", ret); +// return ret; +// } +// ret = aclrtMemcpy(streamBuffer, avctx->extradata_size, avctx->extradata, avctx->extradata_size, +// ACL_MEMCPY_HOST_TO_DEVICE); +// if (ret != 0) { +// av_log(avctx, AV_LOG_ERROR, "Mem copy H2D first packet failed, ret is %d.\n", ret); +// return ret; +// } +// +// hi_vdec_stream stream; +// stream.pts = 0; +// stream.addr = streamBuffer; +// stream.len = avctx->extradata_size; +// stream.end_of_frame = HI_TRUE; +// stream.end_of_stream = HI_FALSE; +// stream.need_display = HI_TRUE; +// +// hi_vdec_pic_info pic_info; +// pic_info.vir_addr = 0; +// pic_info.buffer_size = 0; +// pic_info.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; +// ret = hi_mpi_vdec_send_stream(ctx->channel_id, &stream, &pic_info, VDEC_TIME_OUT); +// if (ret != 0) { +// av_log(avctx, AV_LOG_ERROR, "HiMpi vdec send first packet failed, ret is %d.\n", ret); +// return ret; +// } +// } +// ctx->first_packet = 0; +// } + av_log(avctx, AV_LOG_ERROR, "avpkt->size is %d.\n", avpkt->size); + uint8_t* streamBuffer = NULL; + ret = hi_mpi_dvpp_malloc(ctx->device_id, &streamBuffer, avpkt->size); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi malloc packet failed, ret is %d.\n", ret); + return ret; + } + + ret = aclrtMemcpy(streamBuffer, avpkt->size, avpkt->data, avpkt->size, + ACL_MEMCPY_HOST_TO_DEVICE); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Mem copy H2D first packet failed, ret is %d.\n", ret); + return ret; + } + + // create stream info + hi_vdec_stream stream; + stream.pts = 0; + stream.addr = streamBuffer; + stream.len = avpkt->size; + stream.end_of_frame = HI_TRUE; + stream.end_of_stream = HI_FALSE; + stream.need_display = HI_TRUE; + + ff_mutex_lock(&ctx->queue_mutex); + av_fifo_generic_write(ctx->dts_queue, &avpkt->dts, sizeof(int64_t), NULL); + ff_mutex_unlock(&ctx->queue_mutex); + + // create frame info + hi_vdec_pic_info pic_info; + pic_info.width = ctx->resize_width; // Output image width, supports resize, set 0 means no resize. + pic_info.height = ctx->resize_height; // Output image height, supports resize, set 0 means no resize. + pic_info.width_stride = FFALIGN(ctx->vdec_width, JPEG_DEC_WIDTH_ALIGN); + pic_info.height_stride = FFALIGN(ctx->vdec_height, JPEG_DEC_HEIGHT_ALIGN); + + if (ctx->resize_str && ctx->resize_width != 0 && ctx->resize_height != 0) { + pic_info.width_stride = FFALIGN(ctx->resize_width, JPEG_DEC_WIDTH_ALIGN); + pic_info.height_stride = FFALIGN(ctx->resize_height, JPEG_DEC_HEIGHT_ALIGN); + } + + av_log(avctx, AV_LOG_ERROR, "output width is %d.\n", pic_info.width); + av_log(avctx, AV_LOG_ERROR, "output height is %d.\n", pic_info.height); + av_log(avctx, AV_LOG_ERROR, "output width_stride is %d.\n", pic_info.width_stride); + av_log(avctx, AV_LOG_ERROR, "output height_stride is %d.\n", pic_info.height_stride); + uint32_t size = pic_info.width_stride * pic_info.height_stride * YUV_BGR_CONVERT_3 / YUV_BGR_CONVERT_2; + av_log(avctx, AV_LOG_ERROR, "output size is %d.\n", size); + pic_info.buffer_size = size; + pic_info.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; + void *picBuffer = NULL; + + ret = hi_mpi_dvpp_malloc(ctx->device_id, &picBuffer, size); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi malloc failed, ret is %d.\n", ret); + return ret; + } + pic_info.vir_addr = (uint64_t)picBuffer; + + ret = hi_mpi_vdec_send_stream(ctx->channel_id, &stream, &pic_info, VDEC_TIME_OUT); + +// do { +// ret = hi_mpi_vdec_send_stream(ctx->channel_id, &stream, &pic_info, VDEC_TIME_OUT); +// if ((unsigned int)ret == HI_ERR_VDEC_BUF_FULL) { +// usleep(VDEC_SLEEP_TIME); +// } +// } while ((unsigned int)ret == HI_ERR_VDEC_BUF_FULL); + + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi send stream failed, ret is %d.\n", ret); + return ret; + } + + ctx->frame_id++; + ctx->total_packet_count++; + return 0; +} + +static int hi_mpi_decode(AVCodecContext *avctx, const AVPacket *avpkt) +{ + ASCENDContext_t *ctx = (ASCENDContext_t*) avctx->priv_data; + int ret = 0; + AVPacket packet = { 0 }; + AVPacket bsf_packet = { 0 }; + + hi_vdec_stream stream; + stream.addr = NULL; + stream.len = 0; + stream.end_of_frame = HI_FALSE; + stream.end_of_stream = HI_TRUE; // Stream end flag to flushing all data. + stream.need_display = HI_TRUE; + + hi_vdec_pic_info pic_info; + pic_info.vir_addr = 0; + pic_info.buffer_size = 0; + pic_info.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; + ret = hi_mpi_vdec_send_stream(ctx->channel_id, &stream, &pic_info, -1); + if (ret != 0) { + av_packet_unref(avpkt); + av_log(avctx, AV_LOG_ERROR, "Send last stream failed, ret is %d", ret); + return ret; + } + ctx->decoder_flushing = 1; + + if (!avpkt) { + av_log(avctx, AV_LOG_ERROR, "avpkt is null.\n"); + return -1; + } + + av_log(avctx, AV_LOG_ERROR, "avpkt->size is %d.\n", avpkt->size); + + if (avpkt && avpkt->size && ctx->bsf) { + av_log(avctx, AV_LOG_ERROR, "xxxx"); + ret = av_packet_ref(&packet, avpkt); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "av_packet_ref failed, ret(%d).\n", ret); + return ret; + } + ret = av_bsf_send_packet(ctx->bsf, &packet); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "av_bsf_send_packet failed, ret(%d).\n", ret); + av_packet_unref(&packet); + return ret; + } + ret = av_bsf_receive_packet(ctx->bsf, &bsf_packet); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "av_bsf_receive_packet failed, ret(%d).\n", ret); + return ret; + } + avpkt = &bsf_packet; + } + av_packet_unref(&packet); + + + + if (avpkt && avpkt->size) { + ret = malloc_and_send_frame(avctx, avpkt); + av_log(avctx, AV_LOG_ERROR, "malloc_and_send_frame ret is %d\n", ret); + if (ret != 0) { + av_packet_unref(avpkt); + return AVERROR(EINVAL); + } + } else { + if (!ctx->decoder_flushing) { + hi_vdec_stream stream; + stream.addr = NULL; + stream.len = 0; + stream.end_of_frame = HI_FALSE; + stream.end_of_stream = HI_TRUE; // Stream end flag to flushing all data. + stream.need_display = HI_TRUE; + + hi_vdec_pic_info pic_info; + pic_info.vir_addr = 0; + pic_info.buffer_size = 0; + pic_info.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; + ret = hi_mpi_vdec_send_stream(ctx->channel_id, &stream, &pic_info, -1); + if (ret != 0) { + av_packet_unref(avpkt); + av_log(avctx, AV_LOG_ERROR, "Send last stream failed, ret is %d", ret); + return ret; + } + ctx->decoder_flushing = 1; + } + } + av_log(avctx, AV_LOG_ERROR, "Send last stream failed, ret is %d\n", ret); + av_packet_unref(avpkt); + return 0; +} + +static int himpi_get_frame(AVCodecContext *avctx, AVFrame *frame) +{ + + ASCENDContext_t *ctx = (ASCENDContext_t*)avctx->priv_data; + int ret = 0; + if (!ctx->frame_queue) { + return AVERROR(EAGAIN); + } + + FrameInfo_t frame_info; + ff_mutex_lock(&ctx->queue_mutex); + + av_log(avctx, AV_LOG_ERROR, "av_fifo_size(ctx->frame_queue) is %d \n", av_fifo_size(ctx->frame_queue)); + if (av_fifo_size(ctx->frame_queue) != 0) { + av_fifo_generic_read(ctx->frame_queue, &frame_info, sizeof(FrameInfo_t), NULL); + } else { + ff_mutex_unlock(&ctx->queue_mutex); + return AVERROR(EAGAIN); + } + + ff_mutex_unlock(&ctx->queue_mutex); + + if (frame_info.event_type == EVENT_EOS) { + return AVERROR_EOF; + } + + if (avctx->pix_fmt == AV_PIX_FMT_ASCEND) { + ret = av_hwframe_get_buffer(ctx->hw_frame_ref, frame, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "av_hwframe_get_buffer failed, ret is %d.\n", ret); + return AVERROR(EINVAL); + } + + ret = ff_decode_frame_props(avctx, frame); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "ff_decode_frame_props failed, ret is %d.\n", ret); + return AVERROR(EINVAL); + } + + } else { + ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Decode ff_get_buffer failed, ret is %d.\n", ret); + return AVERROR(EINVAL); + } + } + + frame->pkt_pos = -1; + frame->pkt_duration = 0; + frame->pkt_size = -1; + frame->pts = frame_info.pts; + frame->pkt_pts = frame->pts; + frame->pkt_dts = frame_info.dts; + frame->width = frame_info.width_stride; + frame->height = frame_info.height_stride; + + switch (frame_info.format) { + case HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420: + if (avctx->pix_fmt == AV_PIX_FMT_ASCEND) { + uint32_t offset = 0; + for (int i = 0; i < 2; i++) { + size_t dstBytes = frame->width * frame->height * (i ? 1.0 / 2 : 1); + ret = aclrtMemcpy(frame->data[i], dstBytes, frame_info.data + offset, dstBytes, + ACL_MEMCPY_DEVICE_TO_DEVICE); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Mem copy D2D failed, ret is %d.\n", ret); + hi_mpi_dvpp_free(frame_info.data); + return ret; + } + offset += dstBytes; + } + } else { + uint32_t offset = 0; + for (int i = 0; i < 2; i++) { + size_t dstBytes = frame->width * frame->height * (i ? 1.0 / 2 : 1); + ret = aclrtMemcpy(frame->data[i], dstBytes, frame_info.data + offset, dstBytes, + ACL_MEMCPY_DEVICE_TO_HOST); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Mem copy D2H failed, ret is %d.\n", ret); + hi_mpi_dvpp_free(frame_info.data); + return ret; + } + offset += dstBytes; + } + } + ret = hi_mpi_dvpp_free(frame_info.data); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi free data failed, ret is %d.\n", ret); + } + break; + + default: + hi_mpi_dvpp_free(frame_info.data); + av_log(avctx, AV_LOG_ERROR, "Unsupport pixfmt: %d.\n", (int)frame_info.format); + break; + } + + + return 0; +} + +static int get_frame(AVCodecContext *avctx) +{ +// new + ASCENDContext_t *ctx = (ASCENDContext_t*)avctx->priv_data; + av_log(avctx, AV_LOG_ERROR, "start get frame.\n"); + int ret; + hi_video_frame_info frame; + hi_vdec_stream stream; + hi_vdec_supplement_info stSupplement; + ret = hi_mpi_vdec_get_frame(ctx->channel_id, &frame, &stSupplement, &stream, VDEC_GET_TIME_OUT); + av_log(avctx, AV_LOG_ERROR, "ret is %d.\n", ret); + av_log(avctx, AV_LOG_ERROR, "start hi_mpi_vdec_get_frame.\n"); + if (ret != 0) { + FrameInfo_t frame_info; + memset(&frame_info, 0, sizeof(FrameInfo_t)); + frame_info.event_type = EVENT_EOS; + + ff_mutex_lock(&ctx->queue_mutex); + av_fifo_generic_write(ctx->frame_queue, &frame_info, sizeof(FrameInfo_t), NULL); + ff_mutex_unlock(&ctx->queue_mutex); + sem_post(&ctx->eos_sema); + av_log(avctx, AV_LOG_DEBUG, "Decode got eos.\n"); + return ret; + } + av_log(avctx, AV_LOG_ERROR, "end hi_mpi_vdec_get_frame.\n"); + size_t decResult = frame.v_frame.frame_flag; + + hi_mpi_dvpp_free(stream.addr); + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "HiMpi free stream failed, ret is %d.\n", ret); + return ret; + } + av_log(avctx, AV_LOG_ERROR, "start check decResult.\n"); + av_log(avctx, AV_LOG_ERROR, "decResult is %d.\n", decResult); + if (decResult != 0 && frame.v_frame.virt_addr[0] != NULL) { + hi_mpi_dvpp_free(frame.v_frame.virt_addr[0]); + return ret; + } + av_log(avctx, AV_LOG_ERROR, "end check decResult.\n"); + if (decResult != 0 || frame.v_frame.virt_addr[0] == NULL || stream.need_display == HI_FALSE) { + ret = hi_mpi_vdec_release_frame(ctx->channel_id, &frame); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi release frame failed, ret is %d.", ret); + return ((void*) (-1)); + } + return ret; + } + av_log(avctx, AV_LOG_ERROR, "end hi_mpi_vdec_release_frame.\n"); + FrameInfo_t frame_info; + frame_info.ascend_ctx = ctx; + get_vdec_frame_info(&frame_info, frame); + + ff_mutex_lock(&ctx->queue_mutex); + av_fifo_generic_read(ctx->dts_queue, &frame_info.dts, sizeof(int64_t), NULL); + av_fifo_generic_write(ctx->frame_queue, &frame_info, sizeof(FrameInfo_t), NULL); + ff_mutex_unlock(&ctx->queue_mutex); + av_log(avctx, AV_LOG_DEBUG, "start hi_mpi_vdec_release_frame..\n"); + ret = hi_mpi_vdec_release_frame(ctx->channel_id, &frame); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi release frame failed, ret is %d.\n", ret); + return ret; + } + av_log(avctx, AV_LOG_ERROR, "end hi_mpi_vdec_release_frame..\n"); + ctx->total_out_frame_count++; + // new + return 0; +} + +static int ff_himpi_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + av_log(avctx, AV_LOG_ERROR, "here is ff_himpi_receive_frame 0.\n"); + ASCENDContext_t *ctx = (ASCENDContext_t*)avctx->priv_data; + AVPacket pkt = { 0 }; + int send_ret = -1; + int get_ret = -1; + int ret = 0; + + if (avctx == NULL || avctx->priv_data == NULL) { + av_log(avctx, AV_LOG_ERROR, "ff_himpi_receive_frame error, AVCodecContext is NULL.\n"); + return AVERROR_BUG; + } +// if (!ctx->hi_mpi_init_flag || !ctx->thread_run_flag || !ctx->decode_run_flag) { +// av_log(avctx, AV_LOG_ERROR, "ff_himpi_receive_frame error, AVCodecContext is NULL.\n"); +// return AVERROR_BUG; +// } + + if (!ctx->hi_mpi_init_flag || !ctx->decode_run_flag) { + av_log(avctx, AV_LOG_ERROR, "ff_himpi_receive_frame error, AVCodecContext is NULL.\n"); + return AVERROR_BUG; + } + + av_log(ctx, AV_LOG_ERROR, "ctx->eos_received %d.\n", ctx->eos_received); + if (ctx->eos_received) { + return AVERROR_EOF; + } + + ret = aclrtSetCurrentContext(ctx->ascend_ctx->context); + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "Set context failed, ret is %d.\n", ret); + return ret; + } + + // new + + send_ret = ff_decode_get_packet(avctx, &pkt); + av_log(ctx, AV_LOG_ERROR, "pkt->size is %d.\n", pkt.size); + + if (send_ret < 0 && send_ret != AVERROR_EOF) { + return send_ret; + } + send_ret = hi_mpi_decode(avctx, &pkt); + av_packet_unref(&pkt); + if (send_ret < 0 && send_ret != AVERROR_EOF) { + av_log(ctx, AV_LOG_ERROR, "Send packet failed, ret is %d.\n", send_ret); + return send_ret; + } + + av_log(ctx, AV_LOG_ERROR, "start to get frame.\n"); + ret = get_frame(avctx); + if (ret != 0 && ret != HI_ERR_VDEC_BUF_EMPTY) { + av_log(avctx, AV_LOG_ERROR, "get_frame failed, ret is %d.\n", ret); + return ret; + } + + get_ret = himpi_get_frame(avctx, frame); + av_log(avctx, AV_LOG_ERROR, "get ret is %d.\n", get_ret); + av_log(avctx, AV_LOG_ERROR, "here is ff_himpi_receive_frame 1.\n"); + if (get_ret != 0 && get_ret != AVERROR_EOF) { + if (get_ret != AVERROR(EAGAIN)) { + return get_ret; + } + if (ctx->decoder_flushing) { + av_usleep(2000); + } + } else { + if (get_ret == AVERROR_EOF) { + ctx->eos_received = 1; + } + return get_ret; + } + ctx->eos_received = 1; + + return AVERROR_BUG; +// while (ctx->decode_run_flag) { +// if (!ctx->decoder_flushing) { +// send_ret = ff_decode_get_packet(avctx, &pkt); +// if (send_ret < 0 && send_ret != AVERROR_EOF) { +// return send_ret; +// } +// send_ret = hi_mpi_decode(avctx, &pkt); +// av_packet_unref(&pkt); +// if (send_ret < 0 && send_ret != AVERROR_EOF) { +// av_log(ctx, AV_LOG_ERROR, "Send packet failed, ret is %d.\n", send_ret); +// return send_ret; +// } +// } +// +// get_ret = himpi_get_frame(avctx, frame); +// if (get_ret != 0 && get_ret != AVERROR_EOF) { +// if (get_ret != AVERROR(EAGAIN)) { +// return get_ret; +// } +// if (ctx->decoder_flushing) { +// av_usleep(2000); +// } +// } else { +// if (get_ret == AVERROR_EOF) { +// ctx->eos_received = 1; +// } +// return get_ret; +// } +// } +// +// av_log(avctx, AV_LOG_ERROR, "Decode stop, error.\n"); +// return AVERROR_BUG; + +} + +static av_cold int ff_himpi_decode_init(AVCodecContext *avctx) +{ + ASCENDContext_t *ctx = (ASCENDContext_t*)avctx->priv_data; + AVASCENDDeviceContext *hw_device_ctx; + AVHWFramesContext *hw_frame_ctx; + const AVBitStreamFilter *bsf; + int ret = 0; + + if (avctx == NULL || avctx->priv_data == NULL) { + av_log(avctx, AV_LOG_ERROR, "HiMpi decoder init failed, AVCodecContext is NULL.\n"); + return AVERROR_BUG; + } + + if (ctx->hi_mpi_init_flag == 1) { + av_log(avctx, AV_LOG_ERROR, "Error, himpi decode double init. \n"); + return AVERROR_BUG; + } + + enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_ASCEND, AV_PIX_FMT_NV12, AV_PIX_FMT_NONE }; + avctx->pix_fmt = ff_get_format(avctx, pix_fmts); + av_log(avctx, AV_LOG_ERROR, "INFO, ff_get_format failed with format id: %d.\n", avctx->pix_fmt); + if (avctx->pix_fmt < 0) { + av_log(avctx, AV_LOG_ERROR, "Error, ff_get_format failed with format id: %d.\n", avctx->pix_fmt); + return AVERROR_BUG; + } + + ctx->avctx = avctx; + + if (ctx->resize_str) { + ret = av_parse_video_size(&ctx->resize_width, &ctx->resize_height, ctx->resize_str); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid resize param: %s, which should be {width}x{height}.\n", + ctx->resize_str); + return AVERROR_BUG; + } + + if (ctx->resize_width != FFALIGN(ctx->resize_width, JPEG_DEC_WIDTH_ALIGN) || + ctx->resize_height != FFALIGN(ctx->resize_height, JPEG_DEC_HEIGHT_ALIGN)) { + av_log(avctx, AV_LOG_ERROR, "Invalid resize param: %s, which should be stride by %d and %d.\n", + ctx->resize_str, JPEG_DEC_WIDTH_ALIGN, JPEG_DEC_HEIGHT_ALIGN); + return AVERROR_BUG; + } + + if (ctx->resize_width < 128 || ctx->resize_height < 128 || + ctx->resize_width > 4096 || ctx->resize_height > 4096) { + av_log(avctx, AV_LOG_ERROR, "Invalid resize param: %s, which should be in [128x128 ~ 4096x4096].\n", + ctx->resize_str, JPEG_DEC_WIDTH_ALIGN, JPEG_DEC_HEIGHT_ALIGN); + return AVERROR_BUG; + } + avctx->coded_width = ctx->resize_width; + avctx->coded_height = ctx->resize_height; + } + + if (!ctx->resize_str || (ctx->resize_height == avctx->height && ctx->resize_width == avctx->width)) { + ctx->vdec_width = FFALIGN(avctx->width, JPEG_DEC_WIDTH_ALIGN); + ctx->vdec_height = FFALIGN(avctx->height, JPEG_DEC_HEIGHT_ALIGN); + ctx->resize_width = ctx->resize_height = 0; + } else { + av_log(avctx, AV_LOG_INFO, "Vdec resize: %dx%d.\n", ctx->resize_width, ctx->resize_height); + } + + ctx->vdec_width = avctx->width; + ctx->vdec_height = avctx->height; + + if (decode_params_checking(avctx) != 0) { + return AVERROR(EINVAL); + } + av_log(avctx, AV_LOG_ERROR, "Vdec width: %d.\n", ctx->vdec_width); + av_log(avctx, AV_LOG_ERROR, "Vdec height: %d.\n", ctx->vdec_height); + + if (avctx->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "here is hw_frames_ctx is yes\n"); + av_buffer_unref(&ctx->hw_frame_ref); + ctx->hw_frame_ref = av_buffer_ref(avctx->hw_frames_ctx); + if (!ctx->hw_frame_ref) { + ret = AVERROR(EINVAL); + goto error; + } + + hw_frame_ctx = (AVHWFramesContext*)ctx->hw_frame_ref->data; + if (!hw_frame_ctx->pool || + (ctx->vdec_width != hw_frame_ctx->width && ctx->resize_width != hw_frame_ctx->width)) { + if (hw_frame_ctx->pool) { + av_buffer_pool_uninit(&hw_frame_ctx->pool); + } + hw_frame_ctx->width = ctx->resize_width == 0 ? ctx->vdec_width : ctx->resize_width; + hw_frame_ctx->height = ctx->resize_height == 0 ? ctx->vdec_height : ctx->resize_height; + hw_frame_ctx->initial_pool_size = 2; + hw_frame_ctx->format = AV_PIX_FMT_ASCEND; + hw_frame_ctx->sw_format = avctx->sw_pix_fmt; + + ret = av_hwframe_ctx_init(ctx->hw_frame_ref); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "HWFrame contex init failed.\n"); + return AVERROR(ENAVAIL); + } + } + ctx->hw_device_ref = av_buffer_ref(hw_frame_ctx->device_ref); + if (!ctx->hw_device_ref) { + av_log(avctx, AV_LOG_ERROR, "Get hw_device_ref failed.\n"); + ret = AVERROR(EINVAL); + goto error; + } + } else { + if (avctx->hw_device_ctx) { + ctx->hw_device_ref = av_buffer_ref(avctx->hw_device_ctx); + if (!ctx->hw_device_ref) { + av_log(avctx, AV_LOG_ERROR, "ref hwdevice failed.\n"); + ret = AVERROR(EINVAL); + goto error; + } + } else { + char dev_idx[sizeof(int)]; + sprintf(dev_idx, "%d", ctx->device_id); + av_log(avctx, AV_LOG_INFO, "dev_idx: %s.\n", dev_idx); + ret = av_hwdevice_ctx_create(&ctx->hw_device_ref, AV_HWDEVICE_TYPE_ASCEND, dev_idx, NULL, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "hwdevice contex create failed.\n"); + goto error; + } + } + ctx->hw_frame_ref = av_hwframe_ctx_alloc(ctx->hw_device_ref); + if (!ctx->hw_frame_ref) { + av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_alloc failed, ret is %d.\n", ret); + ret = AVERROR(EINVAL); + goto error; + } + hw_frame_ctx = (AVHWFramesContext*)ctx->hw_frame_ref->data; + if (!hw_frame_ctx->pool) { + hw_frame_ctx->width = ctx->resize_width == 0 ? ctx->vdec_width : ctx->resize_width; + hw_frame_ctx->height = ctx->resize_height == 0 ? ctx->vdec_height : ctx->resize_height; + hw_frame_ctx->initial_pool_size = 2; + hw_frame_ctx->format = AV_PIX_FMT_ASCEND; + hw_frame_ctx->sw_format = avctx->sw_pix_fmt; + ret = av_hwframe_ctx_init(ctx->hw_frame_ref); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "hwframe ctx init error, ret is %d.\n", ret); + return AVERROR(EINVAL); + } + } + } + hw_device_ctx = ((AVHWDeviceContext*)ctx->hw_device_ref->data)->hwctx; + ctx->hw_device_ctx = hw_device_ctx; + ctx->hw_frames_ctx = hw_frame_ctx; + ctx->ascend_ctx = ctx->hw_device_ctx->ascend_ctx; + + ctx->device_id = ctx->ascend_ctx->device_id; + ctx->frame_id = 0; + ctx->eos_received = 0; + ctx->total_out_frame_count = 0; + ctx->total_packet_count = 0; + ctx->decoder_flushing = 0; + ctx->first_packet = 1; + + ff_mutex_init(&ctx->queue_mutex, NULL); + ctx->codec_type = HI_PT_JPEG; + +// switch (avctx->codec->id) +// { +// case AV_CODEC_ID_H264: +// ctx->codec_type = HI_PT_H264; +// break; +// case AV_CODEC_ID_H265: +// ctx->codec_type = HI_PT_H265; +// break; +// default: +// av_log(avctx, AV_LOG_ERROR, "Invalid codec type, %d.\n", avctx->codec->id); +// return AVERROR_BUG; +// } +// ctx->bsf = NULL; +// if (avctx->codec->id == AV_CODEC_ID_H264 || avctx->codec->id == AV_CODEC_ID_H265) { +// if (avctx->codec->id == AV_CODEC_ID_H264) +// bsf = av_bsf_get_by_name("h264_mp4toannexb"); +// else if (avctx->codec->id == AV_CODEC_ID_H265) +// bsf = av_bsf_get_by_name("hevc_mp4toannexb"); +// if (!bsf) { +// ret = AVERROR_BSF_NOT_FOUND; +// goto error; +// } +// ret = av_bsf_alloc(bsf, &ctx->bsf); +// if (ret < 0) +// goto error; +// +// ret = avcodec_parameters_from_context(ctx->bsf->par_in, avctx); +// if (ret < 0) { +// av_bsf_free(&ctx->bsf); +// goto error; +// } +// ret = av_bsf_init(ctx->bsf); +// if (ret < 0) { +// av_bsf_free(&ctx->bsf); +// goto error; +// } +// } else { +// av_log(avctx, AV_LOG_ERROR, "Invalid codec id, %d.\n", avctx->codec->id); +// return AVERROR_BUG; +// } + + ctx->frame_queue = av_fifo_alloc(1 * sizeof(FrameInfo_t)); + if (!ctx->frame_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to alloc frame fifo queue.\n"); + goto error; + } + + ctx->dts_queue = av_fifo_alloc(1 * sizeof(int64_t)); + if (!ctx->dts_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to alloc dts fifo queue.\n"); + goto error; + } + + ret = aclrtSetCurrentContext(ctx->ascend_ctx->context); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Set context failed, ret is %d.\n", ret); + goto error; + } + + ret = hi_mpi_sys_init(); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi sys init failed, ret is %d.\n", ret); + goto error; + } + + ctx->chn_attr_.type = ctx->codec_type; + ctx->chn_attr_.mode = HI_VDEC_SEND_MODE_FRAME; + ctx->chn_attr_.pic_width = ctx->vdec_width; + ctx->chn_attr_.pic_height = ctx->vdec_height; + + // Stream buffer size, Recommended value is width * height * 3 / 2 + ctx->chn_attr_.stream_buf_size = ctx->vdec_width * ctx->vdec_height * YUV_BGR_CONVERT_3 / YUV_BGR_CONVERT_2; + ctx->chn_attr_.frame_buf_cnt = REF_FRAME_NUM + DISPLAY_FRAME_NUM + 1; + + // Create buf attribute + ctx->buf_attr_.width = ctx->chn_attr_.pic_width; + ctx->buf_attr_.height = ctx->chn_attr_.pic_height; + ctx->buf_attr_.align = 0; + ctx->buf_attr_.bit_width = HI_DATA_BIT_WIDTH_8; + ctx->buf_attr_.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; + ctx->buf_attr_.compress_mode = HI_COMPRESS_MODE_NONE; + + ctx->chn_attr_.frame_buf_size = hi_vdec_get_pic_buf_size(ctx->chn_attr_.type, &ctx->buf_attr_); + + // Configure video decoder channel attribute + ctx->chn_attr_.video_attr.ref_frame_num = REF_FRAME_NUM; + ctx->chn_attr_.video_attr.temporal_mvp_en = HI_TRUE; + ctx->chn_attr_.video_attr.tmv_buf_size = hi_vdec_get_tmv_buf_size(ctx->chn_attr_.type, + ctx->chn_attr_.pic_width, + ctx->chn_attr_.pic_height); + + av_log(avctx, AV_LOG_INFO, "Channel Id is: %d.\n", ctx->channel_id); + ret = hi_mpi_vdec_create_chn(ctx->channel_id, &ctx->chn_attr_); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi create vdec channel failed, ret is %d.\n", ret); + goto error; + } + + // reset channel param. + ret = hi_mpi_vdec_get_chn_param(ctx->channel_id, &ctx->chn_param_); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi vdec get channel param failed, ret is %d.\n", ret); + goto error; + } + + ctx->chn_param_.video_param.dec_mode = HI_VIDEO_DEC_MODE_IPB; + ctx->chn_param_.video_param.compress_mode = HI_COMPRESS_MODE_HFBC; + ctx->chn_param_.video_param.video_format = HI_VIDEO_FORMAT_TILE_64x16; + ctx->chn_param_.display_frame_num = DISPLAY_FRAME_NUM; + ctx->chn_param_.video_param.out_order = HI_VIDEO_OUT_ORDER_DISPLAY; + + ret = hi_mpi_vdec_set_chn_param(ctx->channel_id, &ctx->chn_param_); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi vdec set channel param failed, ret is %d.\n", ret); + goto error; + } + + ret = hi_mpi_vdec_start_recv_stream(ctx->channel_id); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "HiMpi vdec start receive stream failed, ret is %d.\n", ret); + goto error; + } + ctx->hi_mpi_init_flag = 1; + ctx->decode_run_flag = 1; + + // create callback thread +// ctx->thread_run_flag = 1; +// ret = pthread_create(&ctx->thread_id, NULL, get_frame, (void *)ctx); +// if (ret != 0) { +// av_log(avctx, AV_LOG_ERROR, "pthread_create callback thread failed, ret is %d.\n", ret); +// goto error; +// } + + avctx->pkt_timebase.num = 1; + avctx->pkt_timebase.den = 90000; + if (!avctx->pkt_timebase.num || !avctx->pkt_timebase.den) { + av_log(avctx, AV_LOG_ERROR, "Invalid pkt_timebase.\n"); + } + + sem_init(&ctx->eos_sema, 0, 0); + return 0; + +error: + sem_post(&ctx->eos_sema); + ff_himpi_decode_end(avctx); + return ret; +} + +static void ff_himpi_flush(AVCodecContext *avctx) { + ff_himpi_decode_end(avctx); + ff_himpi_decode_init(avctx); +} + +#define OFFSET(x) offsetof(ASCENDContext_t, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + { "device_id", "Use to choose the ascend chip.", OFFSET(device_id), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 8, VD}, + { "channel_id", "Set channelId of decoder.", OFFSET(channel_id), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 255, VD}, + { "resize", "Resize (width)x(height).", OFFSET(resize_str), AV_OPT_TYPE_STRING, { .str = NULL}, 0, 0, VD}, + { NULL } +}; + +static const AVCodecHWConfigInternal* ascend_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_ASCEND, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | \ + AV_CODEC_HW_CONFIG_METHOD_INTERNAL, + .device_type = AV_HWDEVICE_TYPE_ASCEND + }, + .hwaccel = NULL, + }, + NULL +}; + +//#define ASCEND_JPEG_DEC_CODEC() \ +// static const AVClass jpeg_ascend_class = { \ +// .class_name = "jpeg_ascend_dec", \ +// .item_name = av_default_item_name, \ +// .option = options, \ +// .version = LIBAVUTIL_VERSION_INT, \ +// }; \ +// AVCodec ff_jpeg_ascend_decoder = { \ +// .name = "jpeg_ascend", \ +// .long_name = NULL_IF_CONFIG_SMALL("Ascend HiMpi jpeg decoder"), \ +// .type = AVMEDIA_TYPE_VIDEO, \ +// .id = AV_CODEC_ID_JPEG2000, \ +// .priv_data_size = sizeof(ASCENDContext_t), \ +// .priv_class = &jpeg_ascend_class, \ +// .init = ff_himpi_decode_init, \ +// .close = ff_himpi_decode_end, \ +// .receive_frame = ff_himpi_receive_frame, \ +// .flush = ff_himpi_flush, \ +// .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ +// .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_ASCEND, \ +// AV_PIX_FMT_NV12, \ +// AV_PIX_FMT_NONE }, \ +// .hw_configs = ascend_hw_configs, \ +// .wrapper_name = "ascendjpegdec", \ +// }; +// +//#if CONFIG_JPEG_ASCEND_DECODER +//ASCEND_JPEG_DEC_CODEC() +//#endif + +#define ASCEND_JPEG_DEC_CODEC(x, X) \ + static const AVClass x##_ascend_class = { \ + .class_name = #x "_ascend_dec", \ + .item_name = av_default_item_name, \ + .option = options, \ + .version = LIBAVUTIL_VERSION_INT, \ + }; \ + AVCodec ff_##x##_ascend_decoder = { \ + .name = #x "_ascend", \ + .long_name = NULL_IF_CONFIG_SMALL("Ascend HiMpi " #X " decoder"), \ + .type = AVMEDIA_TYPE_VIDEO, \ + .id = AV_CODEC_ID_JPEG2000, \ + .priv_data_size = sizeof(ASCENDContext_t), \ + .priv_class = &x##_ascend_class, \ + .init = ff_himpi_decode_init, \ + .close = ff_himpi_decode_end, \ + .receive_frame = ff_himpi_receive_frame, \ + .flush = ff_himpi_flush, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_ASCEND, \ + AV_PIX_FMT_NV12, \ + AV_PIX_FMT_NONE }, \ + .hw_configs = ascend_hw_configs, \ + .wrapper_name = "ascendjpegdec", \ + }; + +#if CONFIG_JPEG_ASCEND_DECODER +ASCEND_JPEG_DEC_CODEC(jpeg, JPEG) +#endif diff --git a/mxVision/Ascendffmpeg/libavcodec/ascend_jpeg_dec.h b/mxVision/Ascendffmpeg/libavcodec/ascend_jpeg_dec.h new file mode 100644 index 0000000000000000000000000000000000000000..ceaf4314c4c9e95db2f8f700cc037ee2917cfd74 --- /dev/null +++ b/mxVision/Ascendffmpeg/libavcodec/ascend_jpeg_dec.h @@ -0,0 +1,146 @@ +/* + * Copyright(c) 2020. Huawei Technologies Co.,Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except int compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FFMPEG_ASCEND_ASCEND_DEC_H +#define FFMPEG_ASCEND_ASCEND_DEC_H + +#include "libavutil/parseutils.h" +#include "libavutil/buffer.h" +#include "libavutil/mathematics.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_ascend.h" +#include "libavutil/fifo.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "libavutil/time.h" +#include "libavutil/common.h" +#include "libavutil/pixdesc.h" +#include "libavutil/thread.h" +#include "libavutil/version.h" +#include "config.h" +#include "avcodec.h" +#include "decode.h" +#include "hwaccels.h" +#include "hwconfig.h" +#include "internal.h" +#include "libavutil/avutil.h" + +#include "acl/dvpp/hi_dvpp.h" + +#define JPEG_DEC_WIDTH_ALIGN 16 +#define JPEG_DEC_HEIGHT_ALIGN 2 + +#define REF_FRAME_NUM 8 +#define DISPLAY_FRAME_NUM 2 +#define VDEC_TIME_OUT 1000 +#define VDEC_GET_TIME_OUT 100 +#define VDEC_SLEEP_TIME 1000 + +#define YUV_BGR_CONVERT_3 3 +#define YUV_BGR_CONVERT_2 2 + +typedef enum { + EVENT_NEW_FRAME = 0, + EVENT_EOS = 1, +} eventType_t; + +typedef struct FrameInfo { + void *ascend_ctx; + eventType_t event_type; + uint8_t *data; + uint32_t data_size; + hi_pixel_format format; + int64_t pts; + int64_t dts; + uint32_t width_stride; + uint32_t height_stride; +} FrameInfo_t; + +typedef struct ASCENDJPEGContext { + AVClass* av_class; + int device_id; + int channel_id; + + volatile int hi_mpi_init_flag; + + /* + struct { + int x; + int y; + int w; + int h; + } crop; + struct { + int width; + int height; + } resize; + */ + + char *output_pixfmt; + sem_t eos_sema; + + AVBufferRef *hw_device_ref; + AVBufferRef *hw_frame_ref; + AVBSFContext *bsf; + AVCodecContext *avctx; + AVFifoBuffer *frame_queue; + AVFifoBuffer *dts_queue; + AVASCENDDeviceContext *hw_device_ctx; + AVHWFramesContext *hw_frames_ctx; + AscendContext *ascend_ctx; + + hi_vdec_chn_attr chn_attr_; + hi_pic_buf_attr buf_attr_; + hi_vdec_chn_param chn_param_; + + AVMutex queue_mutex; + + int max_width; + int max_height; + int vdec_width; + int vdec_height; + int stride_align; + char* resize_str; + int resize_width; + int resize_height; + hi_payload_type codec_type; + + volatile int frame_id; + int first_packet; + volatile int first_seq; + volatile int eos_received; + volatile int decoder_flushing; + volatile int decode_run_flag; + unsigned long long total_packet_count; + unsigned long long total_out_frame_count; + + hi_vdec_stream stream; + hi_vdec_pic_info pic_info; +} ASCENDContext_t; + +static inline void get_vdec_frame_info(FrameInfo_t* frame_info, hi_video_frame_info frame) +{ + uint32_t width_stride = frame.v_frame.width_stride[0]; + uint32_t height_stride = frame.v_frame.height_stride[0]; + frame_info->width_stride = width_stride; + frame_info->height_stride = height_stride; + frame_info->data_size = width_stride * height_stride * YUV_BGR_CONVERT_3 / YUV_BGR_CONVERT_2; + frame_info->format = frame.v_frame.pixel_format; + frame_info->pts = frame.v_frame.pts; + frame_info->data = frame.v_frame.virt_addr[0]; +} + +#endif // FFMPEG_ASCEND_ASCEND_DEC_H \ No newline at end of file diff --git a/mxVision/Ascendffmpeg/libavcodec/decode.c b/mxVision/Ascendffmpeg/libavcodec/decode.c index 936e5d63da8d65db98dd50873bb48959db2d26ec..666fb0a05a852e10fdc3ecbd305c0c5e6b234bc3 100644 --- a/mxVision/Ascendffmpeg/libavcodec/decode.c +++ b/mxVision/Ascendffmpeg/libavcodec/decode.c @@ -543,21 +543,27 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) av_assert0(!frame->buf[0]); if (avctx->codec->receive_frame) { + av_log(avctx, AV_LOG_ERROR, "Here is 546 decode.c.\n"); ret = avctx->codec->receive_frame(avctx, frame); + av_log(avctx, AV_LOG_ERROR, "receive_frame ret is %d.\n", ret); if (ret != AVERROR(EAGAIN)) av_packet_unref(avci->last_pkt_props); } else ret = decode_simple_receive_frame(avctx, frame); - +// av_log(avctx, AV_LOG_ERROR, "AVERROR_EOF is %d.\n", AVERROR_EOF); if (ret == AVERROR_EOF) avci->draining_done = 1; if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS) && - IS_EMPTY(avci->last_pkt_props) && av_fifo_size(avci->pkt_props) >= sizeof(*avci->last_pkt_props)) - av_fifo_generic_read(avci->pkt_props, - avci->last_pkt_props, sizeof(*avci->last_pkt_props), NULL); + IS_EMPTY(avci->last_pkt_props) && av_fifo_size(avci->pkt_props) >= sizeof(*avci->last_pkt_props)) { + av_log(avctx, AV_LOG_ERROR, "Here is 559 decode.c.\n"); + av_fifo_generic_read(avci->pkt_props, + avci->last_pkt_props, sizeof(*avci->last_pkt_props), NULL); + } + if (!ret) { + av_log(avctx, AV_LOG_ERROR, "Here is 566 decode.c.\n"); frame->best_effort_timestamp = guess_correct_pts(avctx, frame->pts, frame->pkt_dts); @@ -614,6 +620,7 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke } if (!avci->buffer_frame->buf[0]) { + av_log(avctx, AV_LOG_ERROR, "Here is avcodec_send_packet.\n"); ret = decode_receive_frame_internal(avctx, avci->buffer_frame); if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) return ret; @@ -662,6 +669,7 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr if (avci->buffer_frame->buf[0]) { av_frame_move_ref(frame, avci->buffer_frame); } else { + av_log(avctx, AV_LOG_ERROR, "here is avcodec_receive_frame "); ret = decode_receive_frame_internal(avctx, frame); if (ret < 0) return ret; @@ -811,6 +819,7 @@ static int compat_decode(AVCodecContext *avctx, AVFrame *frame, while (ret >= 0) { ret = avcodec_receive_frame(avctx, frame); + av_log(avctx, AV_LOG_ERROR, "compat_decode.\n"); if (ret < 0) { if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) ret = 0; @@ -843,14 +852,17 @@ static int compat_decode(AVCodecContext *avctx, AVFrame *frame, finish: if (ret == 0) { /* if there are any bsfs then assume full packet is always consumed */ - if (avctx->codec->bsfs) + if (avctx->codec->bsfs) { + av_log(avctx, AV_LOG_ERROR, "856.\n"); ret = pkt->size; + } + else ret = FFMIN(avci->compat_decode_consumed, pkt->size); } avci->compat_decode_consumed = 0; avci->compat_decode_partial_size = (ret >= 0) ? pkt->size - ret : 0; - + av_log(avctx, AV_LOG_ERROR, "ret is %d.\n", ret); return ret; } @@ -858,6 +870,7 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi int *got_picture_ptr, const AVPacket *avpkt) { + av_log(avctx, AV_LOG_ERROR, "avcodec_decode_video2.\n"); return compat_decode(avctx, picture, got_picture_ptr, avpkt); } diff --git a/mxVision/Ascendffmpeg/libavcodec/hwaccels.h b/mxVision/Ascendffmpeg/libavcodec/hwaccels.h index 879caa659f5be3ac298543e0cb96f8b408a513b2..62689a341164b05f643afc7630835a8dcbc34a1d 100644 --- a/mxVision/Ascendffmpeg/libavcodec/hwaccels.h +++ b/mxVision/Ascendffmpeg/libavcodec/hwaccels.h @@ -45,6 +45,7 @@ extern const AVHWAccel ff_hevc_vdpau_hwaccel; extern const AVHWAccel ff_hevc_videotoolbox_hwaccel; extern const AVHWAccel ff_mjpeg_nvdec_hwaccel; extern const AVHWAccel ff_mjpeg_vaapi_hwaccel; +extern const AVHWAccel ff_mjpeg_ascend_hwaccel; extern const AVHWAccel ff_mpeg1_nvdec_hwaccel; extern const AVHWAccel ff_mpeg1_vdpau_hwaccel; extern const AVHWAccel ff_mpeg1_videotoolbox_hwaccel; diff --git a/mxVision/Ascendffmpeg/libavcodec/mjpegdec.c b/mxVision/Ascendffmpeg/libavcodec/mjpegdec.c index afb117cfc61ab8a04df0bd8f7c133f08eaaac8db..3b57be36edb7863ecd15fb66c040c99b2a3556a7 100644 --- a/mxVision/Ascendffmpeg/libavcodec/mjpegdec.c +++ b/mxVision/Ascendffmpeg/libavcodec/mjpegdec.c @@ -2947,6 +2947,20 @@ static const AVClass mjpegdec_class = { .version = LIBAVUTIL_VERSION_INT, }; + +//static const AVCodecHWConfigInternal* ascend_hw_configs[] = { +// &(const AVCodecHWConfigInternal) { +// .public = { +// .pix_fmt = AV_PIX_FMT_ASCEND, +// .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | \ +// AV_CODEC_HW_CONFIG_METHOD_INTERNAL, +// .device_type = AV_HWDEVICE_TYPE_ASCEND +// }, +// .hwaccel = NULL, +// }, +// NULL +//}; + AVCodec ff_mjpeg_decoder = { .name = "mjpeg", .long_name = NULL_IF_CONFIG_SMALL("MJPEG (Motion JPEG)"), diff --git a/mxVision/Ascendffmpeg/libavformat/utils.c b/mxVision/Ascendffmpeg/libavformat/utils.c index 75e5350a27792350b577c8ef54e60f4d6b4eb665..919d2a89f0528ebdf81c4fd31d8ed224397ae881 100644 --- a/mxVision/Ascendffmpeg/libavformat/utils.c +++ b/mxVision/Ascendffmpeg/libavformat/utils.c @@ -2968,7 +2968,7 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) { - AVCodecContext *avctx = st->internal->avctx; + AVCodecContext *avctx = st->internal->avctx; // st->internal->avctx->pix_fmt #define FAIL(errmsg) do { \ if (errmsg_ptr) \ @@ -4122,6 +4122,11 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ret < 0) goto find_stream_info_err; } + av_log(ic, AV_LOG_WARNING, + "st->internal->info->found_decoder is %d\n", st->internal->info->found_decoder); + av_log(ic, AV_LOG_WARNING, + "st->internal->avctx->pix_fmt is %d\n", st->internal->avctx->pix_fmt); + if (!has_codec_parameters(st, &errmsg)) { char buf[256]; avcodec_string(buf, sizeof(buf), st->internal->avctx, 0);