From: "Dawid Kozinski" <d.kozinski@samsung.com> To: <ffmpeg-devel@ffmpeg.org> Subject: [FFmpeg-devel] [PATCH 3/3] Provided support for MPEG-5 EVC (Essential Video Coding) codec Date: Wed, 20 Apr 2022 14:32:10 +0200 Message-ID: <005601d854b2$a84314b0$f8c93e10$@samsung.com> (raw) In-Reply-To: <CGME20220420123211eucas1p17b2a496278927bf1f15fc3046d30dc83@eucas1p1.samsung.com> - Added muxer for EVC format (MP4, raw) - Added demuxer for EVC format (MP4) - Added evc extension to the list of extensions for ff_mov_demuxer Signed-off-by: Dawid Kozinski <d.kozinski@samsung.com> --- doc/muxers.texi | 6 ++ libavformat/Makefile | 2 + libavformat/allformats.c | 2 + libavformat/evcdec.c | 127 +++++++++++++++++++++++++++++++++++++++ libavformat/isom_tags.c | 2 + libavformat/mov.c | 2 +- libavformat/movenc.c | 28 +++++++++ libavformat/rawenc.c | 13 ++++ 8 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 libavformat/evcdec.c diff --git a/doc/muxers.texi b/doc/muxers.texi index 1af603b7f6..585279c0a4 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -2114,6 +2114,12 @@ DTS Coherent Acoustics (DCA) audio. Dolby Digital Plus, also known as Enhanced AC-3, audio. +@subsection evc + +MPEG-5 Essential Video Coding (EVC) / EVC / MPEG-5 Part 1 EVC video. + +Extensions: evc + @subsection g722 ITU-T G.722 audio. diff --git a/libavformat/Makefile b/libavformat/Makefile index e3233fd7ac..dae53d8b08 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -245,6 +245,8 @@ OBJS-$(CONFIG_HCOM_DEMUXER) += hcom.o pcm.o OBJS-$(CONFIG_HDS_MUXER) += hdsenc.o OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o +OBJS-$(CONFIG_EVC_DEMUXER) += evcdec.o rawdec.o +OBJS-$(CONFIG_EVC_MUXER) += rawenc.o OBJS-$(CONFIG_HLS_DEMUXER) += hls.o hls_sample_encryption.o OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o hlsplaylist.o avc.o OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 7c1d0ac38f..90e45572d2 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -147,6 +147,8 @@ extern const AVInputFormat ff_ea_cdata_demuxer; extern const AVInputFormat ff_eac3_demuxer; extern const AVOutputFormat ff_eac3_muxer; extern const AVInputFormat ff_epaf_demuxer; +extern const AVInputFormat ff_evc_demuxer; +extern const AVOutputFormat ff_evc_muxer; extern const AVOutputFormat ff_f4v_muxer; extern const AVInputFormat ff_ffmetadata_demuxer; extern const AVOutputFormat ff_ffmetadata_muxer; diff --git a/libavformat/evcdec.c b/libavformat/evcdec.c new file mode 100644 index 0000000000..21f3f0f0e4 --- /dev/null +++ b/libavformat/evcdec.c @@ -0,0 +1,127 @@ +/* + * RAW EVC video demuxer + * + * Copyright (c) 2021 Dawid Kozinski <d.kozinski@samsung.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 <xevd.h> + +#include "libavcodec/get_bits.h" +#include "libavcodec/golomb.h" +#include "libavcodec/internal.h" + +#include "rawdec.h" +#include "avformat.h" + +#define EVC_NAL_HEADER_SIZE 2 /* byte */ + +typedef struct EVCParserContext { + int got_sps; + int got_pps; + int got_idr; + int got_nonidr; +} EVCParserContext; + +static int get_nalu_type(const uint8_t *bs, int bs_size) +{ + int nal_unit_type_plus1 = 0; + XEVD_INFO info; + int ret; + + if(bs_size >= EVC_NAL_HEADER_SIZE) { + ret = xevd_info((void*)bs, EVC_NAL_HEADER_SIZE, 1, &info); + if (XEVD_FAILED(ret)) { + av_log(NULL, AV_LOG_ERROR, "Cannot get bitstream information\n"); + return -1; + } + nal_unit_type_plus1 = info.nalu_type; + } + + return nal_unit_type_plus1 - 1; +} + +static uint32_t read_nal_unit_length(const uint8_t *bs, int bs_size) +{ + uint32_t len = 0; + XEVD_INFO info; + int ret; + + if(bs_size >= XEVD_NAL_UNIT_LENGTH_BYTE) { + ret = xevd_info((void *)bs, XEVD_NAL_UNIT_LENGTH_BYTE, 1, &info); + if (XEVD_FAILED(ret)) { + av_log(NULL, AV_LOG_ERROR, "Cannot get bitstream information\n"); + return 0; + } + len = info.nalu_len; + if(len == 0) { + av_log(NULL, AV_LOG_ERROR, "Invalid bitstream size! [%d]\n", bs_size); + return 0; + } + } + + return len; +} + +static int parse_nal_units(const AVProbeData *p, EVCParserContext *ev) +{ + int nalu_type; + size_t nalu_size; + unsigned char *bits = (unsigned char *)p->buf; + int bytes_to_read = p->buf_size; + + while(bytes_to_read > XEVD_NAL_UNIT_LENGTH_BYTE) { + + nalu_size = read_nal_unit_length(bits, XEVD_NAL_UNIT_LENGTH_BYTE); + if(nalu_size == 0) break; + + bits += XEVD_NAL_UNIT_LENGTH_BYTE; + bytes_to_read -= XEVD_NAL_UNIT_LENGTH_BYTE; + + if(bytes_to_read < nalu_size) break; + + nalu_type = get_nalu_type(bits, bytes_to_read); + + bits += nalu_size; + bytes_to_read -= nalu_size; + + if (nalu_type == XEVD_NUT_SPS) + ev->got_sps++; + else if (nalu_type == XEVD_NUT_PPS) + ev->got_pps++; + else if (nalu_type == XEVD_NUT_IDR ) + ev->got_idr++; + else if (nalu_type == XEVD_NUT_NONIDR) + ev->got_nonidr++; + } + + return 0; +} + +static int evc_probe(const AVProbeData *p) +{ + EVCParserContext ev = {}; + int ret = parse_nal_units(p, &ev); + + if (ret == 0 && ev.got_sps && ev.got_pps && (ev.got_idr || ev.got_nonidr > 3)) + return AVPROBE_SCORE_EXTENSION + 1; // 1 more than .mpg + + return 0; +} + +FF_DEF_RAWVIDEO_DEMUXER(evc, "raw EVC video", evc_probe, "evc", AV_CODEC_ID_EVC) diff --git a/libavformat/isom_tags.c b/libavformat/isom_tags.c index 62e60470a8..0245cfb999 100644 --- a/libavformat/isom_tags.c +++ b/libavformat/isom_tags.c @@ -145,6 +145,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_H264, MKTAG('d', 'v', 'a', '1') }, /* AVC-based Dolby Vision derived from avc1 */ { AV_CODEC_ID_H264, MKTAG('d', 'v', 'a', 'v') }, /* AVC-based Dolby Vision derived from avc3 */ + { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') }, /* EVC/MPEG-5 */ + { AV_CODEC_ID_VP8, MKTAG('v', 'p', '0', '8') }, /* VP8 */ { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') }, /* VP9 */ { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') }, /* AV1 */ diff --git a/libavformat/mov.c b/libavformat/mov.c index 6c847de164..0719f27ce8 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -8882,7 +8882,7 @@ const AVInputFormat ff_mov_demuxer = { .long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"), .priv_class = &mov_class, .priv_data_size = sizeof(MOVContext), - .extensions = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v", + .extensions = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v,evc", .flags_internal = FF_FMT_INIT_CLEANUP, .read_probe = mov_probe, .read_header = mov_read_header, diff --git a/libavformat/movenc.c b/libavformat/movenc.c index b9956e699c..9116baf01b 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -1373,6 +1373,17 @@ static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track) return update_size(pb, pos); } +static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track) +{ + int64_t pos = avio_tell(pb); + + avio_wb32(pb, 0); + ffio_wfourcc(pb, "evcC"); + ff_isom_write_avcc(pb, track->vos_data, track->vos_len); + + return update_size(pb, pos); +} + /* also used by all avid codecs (dv, imx, meridien) and their variants */ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) { @@ -1622,6 +1633,16 @@ static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track) return tag; } +static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track) +{ + int tag = track->par->codec_tag; + + if (!tag) + tag = MKTAG('e', 'v', 'c', 'i'); + + return tag; +} + static const struct { enum AVPixelFormat pix_fmt; uint32_t tag; @@ -1703,6 +1724,8 @@ static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track) tag = mov_get_mpeg2_xdcam_codec_tag(s, track); else if (track->par->codec_id == AV_CODEC_ID_H264) tag = mov_get_h264_codec_tag(s, track); + else if (track->par->codec_id == AV_CODEC_ID_EVC) + tag = mov_get_evc_codec_tag(s, track); else if (track->par->codec_id == AV_CODEC_ID_DNXHD) tag = mov_get_dnxhd_codec_tag(s, track); else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -2239,6 +2262,9 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex mov_write_avcc_tag(pb, track); if (track->mode == MODE_IPOD) mov_write_uuid_tag_ipod(pb); + } + else if (track->par->codec_id ==AV_CODEC_ID_EVC) { + mov_write_evcc_tag(pb, track); } else if (track->par->codec_id == AV_CODEC_ID_VP9) { mov_write_vpcc_tag(mov->fc, pb, track); } else if (track->par->codec_id == AV_CODEC_ID_AV1) { @@ -5767,6 +5793,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) if ((par->codec_id == AV_CODEC_ID_DNXHD || par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_HEVC || + par->codec_id == AV_CODEC_ID_EVC || par->codec_id == AV_CODEC_ID_TRUEHD || par->codec_id == AV_CODEC_ID_AC3) && !trk->vos_len && !TAG_IS_AVCI(trk->tag)) { @@ -7332,6 +7359,7 @@ static const AVCodecTag codec_mp4_tags[] = { { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') }, { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, + { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') }, { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') }, diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c index efdfd0b0aa..bd2b4c6400 100644 --- a/libavformat/rawenc.c +++ b/libavformat/rawenc.c @@ -401,6 +401,19 @@ const AVOutputFormat ff_hevc_muxer = { }; #endif +#if CONFIG_EVC_MUXER +AVOutputFormat ff_evc_muxer = { + .name = "evc", + .long_name = NULL_IF_CONFIG_SMALL("raw EVC video"), + .extensions = "evc", + .audio_codec = AV_CODEC_ID_NONE, + .video_codec = AV_CODEC_ID_EVC, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + #if CONFIG_M4V_MUXER const AVOutputFormat ff_m4v_muxer = { .name = "m4v", -- 2.17.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next parent reply other threads:[~2022-04-20 12:32 UTC|newest] Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top [not found] <CGME20220420123211eucas1p17b2a496278927bf1f15fc3046d30dc83@eucas1p1.samsung.com> 2022-04-20 12:32 ` Dawid Kozinski [this message] [not found] <CGME20220622064910eucas1p278476f244706d9b333bcead6670bb8c5@eucas1p2.samsung.com> 2022-06-22 6:49 ` Dawid Kozinski [not found] <CGME20220512060540eucas1p2d1d882eab8eb0e14d154a890a5dde735@eucas1p2.samsung.com> 2022-05-12 6:05 ` Dawid Kozinski [not found] <CGME20220420095428eucas1p10af334bf2cfab73dd91e5c29037b225c@eucas1p1.samsung.com> 2022-04-20 9:54 ` Dawid Kozinski
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to='005601d854b2$a84314b0$f8c93e10$@samsung.com' \ --to=d.kozinski@samsung.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git