From patchwork Wed Jul 21 17:28:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Jan_Ekstr=C3=B6m?= X-Patchwork-Id: 28998 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a5d:965a:0:0:0:0:0 with SMTP id d26csp6384442ios; Wed, 21 Jul 2021 10:28:26 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz9RwkmacRMkjomdzIZ28XlDqKB2N4QNTZjP2r0Tpijbxp2EvUQu6/XcK8ZeC0PCh6AGF/J X-Received: by 2002:a50:ed91:: with SMTP id h17mr48603737edr.133.1626888506005; Wed, 21 Jul 2021 10:28:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626888506; cv=none; d=google.com; s=arc-20160816; b=oUvJ4yJO4XBgdwbnKQX8DSew6nHQGfjrXULqFahGJysJUSL9VYzyqI7MVDbVx5ey6q wCt31/k9XvnVGi1AstVIS8cNSe1pFuC+MaRA19yxs7gScwE7ft1wSIuovu00P44KINJ8 BhZN35JnPAb+ad8m9nNGMJi4JEMayPtSgleNal2gMr21CNLPGrldMwtbWaEOBC7lmSzw IOecKXByq4KGnxmS7fnqz6fFWkV2oQIEmou0csX9lsHF8TnkAvS961Z0l96O1ZFGNSEZ zQZseEQ2Am0ISpkNNH8qV3XAFZ3tGMJNwrWbgVhsOPH0zMTCwf9CPQpMfsJeaN+9u7J/ ZZVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=qybItZggKJikhvRlBw3NJlW6ZuYxtbygK2STWVGfDNQ=; b=H4HbB24lTSRVMvqixuD60dGeOTFVLQpZqH51MXcLuR+thxLM2p8aR4m/46yuFidHY1 uzK8Ij96pcTpuItRdzVbO+6aEzTCeMaos6xQ9ZWNeFS3XE39Yzy2u/h22w7nqCsm0yCj LFBsvOmyfk3Mx7z+MfO4UjU1YbOD4TDvYBGxlZkMI6qwIwe57Fd3RWwOpcBbvqN7UEXm HZO687ZbQzez7bNVVJVAW40PcgGTy/0CTjif0ppsRyhT5bVhxVv3OLQ1IbkdcrWhiw9c qJSr1zaITT4GCvt6ouxR3bVjd7tXh0tEVVlsPi78o2Qiqc5DKJsBQ9yhXVCReayhNSx5 KIHA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=LTWbgNNq; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id s15si21732032edd.474.2021.07.21.10.28.25; Wed, 21 Jul 2021 10:28:25 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=LTWbgNNq; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id DBE9868A94E; Wed, 21 Jul 2021 20:28:22 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f174.google.com (mail-lj1-f174.google.com [209.85.208.174]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 6BF1068A15F for ; Wed, 21 Jul 2021 20:28:16 +0300 (EEST) Received: by mail-lj1-f174.google.com with SMTP id u14so4040976ljh.0 for ; Wed, 21 Jul 2021 10:28:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=TCyjpR15yKbP6SY8ngMZ14U5KNeimSZO6IB3OQHKn20=; b=LTWbgNNq9VZ2upouqIr6h3XpdXijxNmi5LIYZnP7Bn+jc3fGNUfHywLjNX1oOkPgaD 2zN8HMRSPE9FEfNZLM691gVqWa3Dz8tyAvQ0zajFBh/R7FCOygWh59rh7EtyflDK7zcW txyV/hLIpqSNRNpEJaRPKDQu2sfYySNjmgrd2EMfZt8Um6fVmXiIXI0E0vFhzvPhxhtW 3/hb9OZdv3v3mUek689g3ML36Y7lHRS4YmPT7ULJIJYcjtHhiebiyof9ppvD3lLlmNGt 6oyX1svyZMEb7yYdBPhJmvEntt7cYTQsep7oHW1PKhT2vnnBPAs2GqCV7MKJe/tapwpR RRBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=TCyjpR15yKbP6SY8ngMZ14U5KNeimSZO6IB3OQHKn20=; b=HJ1LUrO55iysRm4T+Z4xnVwv0PLHJsSrkLoJULs8IQkrY5r2Y9Tj2Q8DKsPHcfaxjT l3zWw5ijW7bHkG/ra6pDjRye5XcqmjlQsW3iP5AVNoaCZZJi/hO0asNMTe0u8Ao2NGOI WEEw4oCw1YWW3XZGR/CIRhOej9ayE4U+ozlI37nkQpxK6gYpz/co/uK5rWFZzwFl8ABP RjWD16vtFgLL4FeJGajsVaJg8AnU6gtFnLhAip838Md1g5S4UeCh58FWQngNVy/yLWVt IE5Td79r5SvbWlWqZMx6cGqAjt7KLPoVbw2hLZjqHwdiKZCgUTVyY4s119MGfbNVtv/Z YFtA== X-Gm-Message-State: AOAM533stKhHkqpSv+TE3arRIs587l8YmRfp9ZgeuAJqOeW6lsh8fPw7 W4lJobUa2PueDj/rtoda7dBWRbllPAjegg== X-Received: by 2002:a2e:9901:: with SMTP id v1mr31690133lji.205.1626888495599; Wed, 21 Jul 2021 10:28:15 -0700 (PDT) Received: from localhost.localdomain (91-159-194-103.elisa-laajakaista.fi. [91.159.194.103]) by smtp.gmail.com with ESMTPSA id b14sm1823960lfb.132.2021.07.21.10.28.14 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Jul 2021 10:28:15 -0700 (PDT) From: =?utf-8?q?Jan_Ekstr=C3=B6m?= To: ffmpeg-devel@ffmpeg.org Date: Wed, 21 Jul 2021 20:28:09 +0300 Message-Id: <20210721172809.22974-1-jeebjp@gmail.com> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat/mov: parse 3gpp titl from media or track udta X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: NZCqgemWw22I Seems to be utilized by Handbrake for track titling and is actually defined as "title for the media" as per the specification. Definition from 3GPP TS 26.244 follows: Field Type Details Value BoxHeader.Size Unsigned int(32) BOX_SIZE BoxHeader.Type Unsigned int(32) 'titl' BoxHeader.Version Unsigned int(8) 0 BoxHeader.Flags Bit(24) 0 Pad Bit(1) 0 Language Unsigned int(5)[3] Packed ISO-639-2/T language code Title String Text of title Semantics: Language: declares the language code for the following text. See ISO 639-2/T for the set of three character codes. Each character is packed as the difference between its ASCII value and 0x60. The code is confined to being three lower-case letters, so these values are strictly positive. Title: null-terminated string in either UTF-8 or UTF-16 characters, giving a title information. If UTF-16 is used, the string shall start with the BYTE ORDER MARK (0xFEFF). --- libavformat/mov.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/libavformat/mov.c b/libavformat/mov.c index 040babed95..9edb3d6596 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -291,6 +291,111 @@ static int mov_metadata_hmmt(MOVContext *c, AVIOContext *pb, unsigned len) return 0; } +// 3GPP TS 26.244, 8.2 3GPP asset meta data +static int mov_metadata_titl(MOVContext *c, AVIOContext *pb, unsigned len) +{ + AVFormatContext *s = c->fc; + int version = -1, ret = AVERROR_BUG; + unsigned left_bytes = len, langcode = 0, flags = 100, bom = 0, buf_size = 0; + char language[4] = { 0 }; + AVStream *st = NULL; + char *title_buf = NULL; + const char key[] = "title"; + + // 4 byte FullBox header, 2 byte lang. code, at least 1 byte for string + if (len < 4 + 2 + 1) { + av_log(s, AV_LOG_ERROR, "3GPP titl box too short!\n"); + return AVERROR_INVALIDDATA; + } + + if (s->nb_streams >= 1) + st = s->streams[s->nb_streams-1]; + + // FullBox header + version = avio_r8(pb); + flags = avio_rb24(pb); + left_bytes -= 4; + + if (version != 0 || flags != 0) { + av_log(s, AV_LOG_ERROR, + "Invalid nonzero version (%d) or flags (%x) for 3GPP titl!\n", + version, flags); + return AVERROR_INVALIDDATA; + } + + langcode = avio_rb16(pb) & ~(1 << 15); + if ((ret = ff_mov_lang_to_iso639(langcode, language)) < 0) { + av_log(s, AV_LOG_ERROR, + "Failed to parse 3GPP titl language code %x: %s!\n", + langcode, av_err2str(ret)); + return ret; + } + + left_bytes -= 2; + + if (left_bytes <= 1) + // no contents (just null) + return 0; + + buf_size = left_bytes + 1; + if (!(title_buf = av_mallocz(buf_size))) { + av_log(s, AV_LOG_ERROR, + "Could not allocate buffer of length %u for parsed 3GPP titl " + "title string!\n", + left_bytes); + return AVERROR(ENOMEM); + } + + bom = avio_rb16(pb); + left_bytes -= 2; + + if (bom == 0xfeff) + avio_get_str16be(pb, left_bytes, title_buf, buf_size); + else if (bom == 0xfffe) + avio_get_str16le(pb, left_bytes, title_buf, buf_size); + else { + AV_WB16(title_buf, bom); + if (!left_bytes) + title_buf[2] = 0; + else + avio_get_str(pb, left_bytes, title_buf + 2, buf_size - 2); + } + + av_log(s, AV_LOG_TRACE, "%s TitlBox(lang: %s, title: %s)\n", + st ? "track" : "media", + language, title_buf); + + s->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; + + if (*language && strcmp(language, "und")) { + char lang_key[sizeof(key) + 1 + sizeof(language)] = { 0 }; + snprintf(lang_key, sizeof(lang_key), "%s-%s", key, language); + + if ((ret = av_dict_set(st ? &st->metadata : &s->metadata, + lang_key, title_buf, 0)) < 0) { + av_log(s, AV_LOG_ERROR, + "Failed to set %s metadata key %s to value %s: %s!\n", + st ? "track" : "media", + lang_key, title_buf, + av_err2str(ret)); + goto cleanup; + } + } + + ret = av_dict_set(st ? &st->metadata : &s->metadata, key, title_buf, 0); + if (ret < 0) + av_log(s, AV_LOG_ERROR, + "Failed to set %s metadata key %s to value %s: %s!\n", + st ? "track" : "media", + key, title_buf, + av_err2str(ret)); + +cleanup: + av_freep(&title_buf); + + return ret; +} + static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) { char tmp_key[AV_FOURCC_MAX_STRING_SIZE] = {0}; @@ -349,6 +454,8 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) case MKTAG( 's','o','s','n'): key = "sort_show"; break; case MKTAG( 's','t','i','k'): key = "media_type"; parse = mov_metadata_int8_no_padding; break; + case MKTAG( 't','i','t','l'): + return mov_metadata_titl(c, pb, atom.size); case MKTAG( 't','r','k','n'): key = "track"; parse = mov_metadata_track_or_disc_number; break; case MKTAG( 't','v','e','n'): key = "episode_id"; break;