From patchwork Tue Jul 20 21:10:03 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: 29000 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a5d:965a:0:0:0:0:0 with SMTP id d26csp6395239ios; Wed, 21 Jul 2021 10:47:37 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxC/kmyxGVws1X+6VCAuhsR8HFAs1hT11M5NQYEkqtdBPgxhG+bMQGcx0Ck4k6g9QgKWLs1 X-Received: by 2002:aa7:cb56:: with SMTP id w22mr11446702edt.234.1626889657249; Wed, 21 Jul 2021 10:47:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626889657; cv=none; d=google.com; s=arc-20160816; b=tStXDpwM39Imsi1ygZ8dP7f3P0QQWb9GhF1zyM/oXN7q6OMVZp13pozoxPHQkANsWg 1FY8qtneEZs9lc7hVv8PdCzUcvYQMNsbF4EqP5orMaHQx15ZkbNSyKwWDgZ3vqFWqINn EsXAybbJ0l7CpJljWOfdr2QrQAgjD60jRVjNBNCPpsZ//kV6nKyxp0a9Ynhr1uBdapME Q57morGWUCiPWT1hInGZvDWSuY7O0kHa+Zka1E/ry7h5EOgc1Pm1f2CIY42lnoAtZPeQ d0u6gggi8dNuIpDaRU3F3emOxIa7gSHBPaVz6rf77dBe+r4fGXnecJgo51PZc/JCNmPm JHUQ== 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=LamXmMDdIN4CUrNK7HGlya6nl1ghBOLIGrj5ej5vbCE=; b=XXaPLqvf4D2+S8t3Ql/AhjdIFUa1+K3cT9jla0miB04amwhhYJNjy76Yi5CyEAxu0Q MzGPU5PdtLUbR2ol428MHxHjEsGMkKSgv3aNYNAn/cSHHM6Ic+LVYWybYohxxp3CyXYn pR8QOeV1q18LhVEanPd0jS1xxLqF7Aa+EKw3qgObzmua+48MYnCpSHxbAm9gDW3yJolB doWbKM6Rca8Ut3P28n0Eyn0DS9j4LZhe2GmNk8+mVmQhBFsbeoNuVPQw8wPs9AlJp8uc pEkFX3o8GGV9wUpWTfTGFRFaoZx7Wpm/m1mTUUto0zbPspXzt2sngxUCh/yTvWxpFNzU jN6Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=uVTJisMp; 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 ks1si27441887ejb.49.2021.07.21.10.47.36; Wed, 21 Jul 2021 10:47:37 -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=uVTJisMp; 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 8F49168A94E; Wed, 21 Jul 2021 20:47:32 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f170.google.com (mail-lj1-f170.google.com [209.85.208.170]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C9D4068A5CB for ; Wed, 21 Jul 2021 20:47:25 +0300 (EEST) Received: by mail-lj1-f170.google.com with SMTP id b16so2785110ljq.9 for ; Wed, 21 Jul 2021 10:47:25 -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=VQSappb2ijkdcfKo7ugJJSQgHtoOynVd+EQPuvijMas=; b=uVTJisMpTeWblew8aKxspMFRYJr72WzvzPAiLkHZRVhp38pSDL5GHdbuGlnR0Iy97H WcQLXvNCrdWP9IJUxqyMD2Sl4X4xC0smZswzHhNf2zXhE2Hmrga9iyMuLuQT4Col9rSJ FhuWglrOd0pc7+sgWRnPOyKXOFNA4bh0Umzk15oxhbVbOvUZ1zvDwVYEYnQ/7EM0wdw/ V4jgQhMQfWKFfpc4FSUOIpLi93yJzT/DXJxrpGDPk8L3Y4QqeJY3YhBcwKK5p6zOYJtn XI65FQd41byNdPz36X1MuhlRL1jyR5JaQt/P75ZWcwVaYy8F7cSbUl7S+qPviKu3Hlc2 CLjg== 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=VQSappb2ijkdcfKo7ugJJSQgHtoOynVd+EQPuvijMas=; b=tr+xrthh5lWNYaMkku2gO2JW4zuAnpXIzmW9nuGttrjnkq3JEoeeWOFk1JyuLyHkCr OWMY1QXgaoa+ntiDKI+k5FztoVYnzOixAwNN9VEg1+ZmEdfTScXph+/StzcyfFc9BLNv Z/CmNVGLqb5I54iyXdQMSNzSptzniFub5EwTm26OhXYV/9ixu+KDH5UFSyh0/rFOm0lq xSlfcYwwEhpOcTGh/1L67bk5gaanmiQVS2URNSfiLU5ceqaFs1yXXaFRSggKPU1qOINW k0EMWy8zbeObI/chRsmTTG7uOrLWflM1k86DsbWCNdRBIBhu7bd4hDETSdwB7+BB/uyQ U1SQ== X-Gm-Message-State: AOAM533vZvaFtMYVK7VHON06jOnpYI/c4sIQ1DtZc3llqgLBuRLaIEWT 4n3h0E4/Sbm/xm8jlgpVwZ0p6XwsbDcRdw== X-Received: by 2002:a05:651c:88d:: with SMTP id d13mr25704161ljq.505.1626815411169; Tue, 20 Jul 2021 14:10:11 -0700 (PDT) Received: from localhost.localdomain (91-159-194-103.elisa-laajakaista.fi. [91.159.194.103]) by smtp.gmail.com with ESMTPSA id m25sm1579050lfo.247.2021.07.20.14.10.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Jul 2021 14:10:09 -0700 (PDT) From: =?utf-8?q?Jan_Ekstr=C3=B6m?= To: ffmpeg-devel@ffmpeg.org Date: Wed, 21 Jul 2021 00:10:03 +0300 Message-Id: <20210720211003.49697-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: Kuy5wNapbF+T Seems to be: * Utilized by Handbrake for track titling * Actually defined as "title for the media" 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;