diff mbox series

[FFmpeg-devel] avformat/isom: allow ISO 639 codes for mov

Message ID 20200620001006.159305-1-yonglel@google.com
State New
Headers show
Series [FFmpeg-devel] avformat/isom: allow ISO 639 codes for mov | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Yongle Lin June 20, 2020, 12:10 a.m. UTC
Allow ISO 639 language codes for text tracks in mov format when
strictness is set to experimental
---
 libavformat/isom.c             | 9 +++++++--
 libavformat/isom.h             | 2 +-
 libavformat/movenc.c           | 6 +++---
 tests/fate/mov.mak             | 3 +++
 tests/ref/fate/mov-iso639-lang | 4 ++++
 5 files changed, 18 insertions(+), 6 deletions(-)
 create mode 100644 tests/ref/fate/mov-iso639-lang

Comments

Yongle Lin July 6, 2020, 6:04 p.m. UTC | #1
On Fri, Jun 19, 2020 at 5:11 PM Yongle Lin <yongle.lin.94@gmail.com> wrote:

> Allow ISO 639 language codes for text tracks in mov format when
> strictness is set to experimental
> ---
>  libavformat/isom.c             | 9 +++++++--
>  libavformat/isom.h             | 2 +-
>  libavformat/movenc.c           | 6 +++---
>  tests/fate/mov.mak             | 3 +++
>  tests/ref/fate/mov-iso639-lang | 4 ++++
>  5 files changed, 18 insertions(+), 6 deletions(-)
>  create mode 100644 tests/ref/fate/mov-iso639-lang
>
> diff --git a/libavformat/isom.c b/libavformat/isom.c
> index 44c7b13038..de20ea8d8b 100644
> --- a/libavformat/isom.c
> +++ b/libavformat/isom.c
> @@ -416,7 +416,7 @@ static const char mov_mdhd_language_map[][4] = {
>      "cat", "lat", "que", "grn", "aym", "tat", "uig", "dzo", "jav"
>  };
>
> -int ff_mov_iso639_to_lang(const char lang[4], int mp4)
> +int ff_mov_iso639_to_lang(const char lang[4], int mp4, int
> strict_std_compliance)
>  {
>      int i, code = 0;
>
> @@ -426,8 +426,13 @@ int ff_mov_iso639_to_lang(const char lang[4], int mp4)
>              return i;
>      }
>      /* XXX:can we do that in mov too? */
> -    if (!mp4)
> +    if (!mp4 && (strict_std_compliance != FF_COMPLIANCE_EXPERIMENTAL ||
> !strcmp(lang, "und"))) {
> +        if (strcmp(lang, "und"))
> +            av_log(NULL, AV_LOG_WARNING, "Non macintosh language is
> discarded for mov\n");
>          return -1;
> +    }
> +    if (!mp4)
> +        av_log(NULL, AV_LOG_WARNING, "Experimental behavior: enable iso
> 639 language in mov\n");
>      /* handle undefined as such */
>      if (lang[0] == '\0')
>          lang = "und";
> diff --git a/libavformat/isom.h b/libavformat/isom.h
> index 41a9c64c11..9d018ebf1f 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -43,7 +43,7 @@ extern const AVCodecTag ff_codec_movaudio_tags[];
>  extern const AVCodecTag ff_codec_movsubtitle_tags[];
>  extern const AVCodecTag ff_codec_movdata_tags[];
>
> -int ff_mov_iso639_to_lang(const char lang[4], int mp4);
> +int ff_mov_iso639_to_lang(const char lang[4], int mp4, int
> strict_std_compliance);
>  int ff_mov_lang_to_iso639(unsigned code, char to[4]);
>
>  struct AVAESCTR;
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 520aaafb74..4d7a98245e 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -3429,7 +3429,7 @@ static int mov_write_string_data_tag(AVIOContext
> *pb, const char *data, int lang
>          return size;
>      } else {
>          if (!lang)
> -            lang = ff_mov_iso639_to_lang("und", 1);
> +            lang = ff_mov_iso639_to_lang("und", 1, FF_COMPLIANCE_NORMAL);
>          avio_wb16(pb, strlen(data)); /* string length */
>          avio_wb16(pb, lang);
>          avio_write(pb, data, strlen(data));
> @@ -3468,7 +3468,7 @@ static AVDictionaryEntry
> *get_metadata_lang(AVFormatContext *s,
>      while ((t2 = av_dict_get(s->metadata, tag2, t2,
> AV_DICT_IGNORE_SUFFIX))) {
>          len2 = strlen(t2->key);
>          if (len2 == len + 4 && !strcmp(t->value, t2->value)
> -            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
> +            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1,
> s->strict_std_compliance)) >= 0) {
>              *lang = l;
>              return t;
>          }
> @@ -6445,7 +6445,7 @@ static int mov_init(AVFormatContext *s)
>
>          track->st  = st;
>          track->par = st->codecpar;
> -        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und",
> mov->mode!=MODE_MOV);
> +        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und",
> mov->mode!=MODE_MOV, s->strict_std_compliance);
>          if (track->language < 0)
>              track->language = 32767;  // Unspecified Macintosh language
> code
>          track->mode = mov->mode;
> diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
> index 7a721d7c95..a85cc1a07d 100644
> --- a/tests/fate/mov.mak
> +++ b/tests/fate/mov.mak
> @@ -29,6 +29,7 @@ FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \
>                     fate-mov-guess-delay-2 \
>                     fate-mov-guess-delay-3 \
>                     fate-mov-mp4-with-mov-in24-ver \
> +                   fate-mov-iso639-lang \
>
>  FATE_MOV_FASTSTART = fate-mov-faststart-4gb-overflow \
>
> @@ -124,3 +125,5 @@ fate-mov-faststart-4gb-overflow: CMP = oneline
>  fate-mov-faststart-4gb-overflow: REF = bc875921f151871e787c4b4023269b29
>
>  fate-mov-mp4-with-mov-in24-ver: CMD = run ffprobe$(PROGSSUF)$(EXESUF)
> -show_entries stream=codec_name -select_streams 1
> $(TARGET_SAMPLES)/mov/mp4-with-mov-in24-ver.mp4
> +
> +fate-mov-iso639-lang: CMD = ffmpeg$(PROGSSUF)$(EXESUF) -f lavfi -i
> sine=frequency=1000:duration=15 -strict experimental -metadata:s:a:0
> language=deu -y $(TARGET_PATH)/metadata.mov; run ffprobe -show_entries
> stream=index:stream_tags=language $(TARGET_PATH)/metadata.mov; rm
> metadata.mov
> diff --git a/tests/ref/fate/mov-iso639-lang
> b/tests/ref/fate/mov-iso639-lang
> new file mode 100644
> index 0000000000..6d1f61169d
> --- /dev/null
> +++ b/tests/ref/fate/mov-iso639-lang
> @@ -0,0 +1,4 @@
> +[STREAM]
> +index=0
> +TAG:language=deu
> +[/STREAM]
> --
> 2.27.0.111.gc72c7da667-goog
>
> Dear FFmpeg Developers,

Could you please review this patch when you have time. Thanks.

Best,
Yongle
Baptiste Coudurier July 6, 2020, 10:15 p.m. UTC | #2
Hi Yongle, I hope you are doing well

> On Jul 6, 2020, at 11:04 AM, Yongle Lin <yongle.lin.94@gmail.com> wrote:
> 
> On Fri, Jun 19, 2020 at 5:11 PM Yongle Lin <yongle.lin.94@gmail.com <mailto:yongle.lin.94@gmail.com>> wrote:
> 
>> Allow ISO 639 language codes for text tracks in mov format when
>> strictness is set to experimental
>> ---
>> libavformat/isom.c             | 9 +++++++--
>> libavformat/isom.h             | 2 +-
>> libavformat/movenc.c           | 6 +++---
>> tests/fate/mov.mak             | 3 +++
>> tests/ref/fate/mov-iso639-lang | 4 ++++
>> 5 files changed, 18 insertions(+), 6 deletions(-)
>> create mode 100644 tests/ref/fate/mov-iso639-lang
>> 
>> diff --git a/libavformat/isom.c b/libavformat/isom.c
>> index 44c7b13038..de20ea8d8b 100644
>> --- a/libavformat/isom.c
>> +++ b/libavformat/isom.c
>> @@ -416,7 +416,7 @@ static const char mov_mdhd_language_map[][4] = {
>>     "cat", "lat", "que", "grn", "aym", "tat", "uig", "dzo", "jav"
>> };
>> 
>> -int ff_mov_iso639_to_lang(const char lang[4], int mp4)
>> +int ff_mov_iso639_to_lang(const char lang[4], int mp4, int
>> strict_std_compliance)
>> {
>>     int i, code = 0;
>> 
>> @@ -426,8 +426,13 @@ int ff_mov_iso639_to_lang(const char lang[4], int mp4)
>>             return i;
>>     }
>>     /* XXX:can we do that in mov too? */
>> -    if (!mp4)
>> +    if (!mp4 && (strict_std_compliance != FF_COMPLIANCE_EXPERIMENTAL ||
>> !strcmp(lang, "und"))) {
>> +        if (strcmp(lang, "und"))
>> +            av_log(NULL, AV_LOG_WARNING, "Non macintosh language is
>> discarded for mov\n");
>>         return -1;
>> +    }
>> +    if (!mp4)
>> +        av_log(NULL, AV_LOG_WARNING, "Experimental behavior: enable iso
>> 639 language in mov\n");
>>     /* handle undefined as such */
>>     if (lang[0] == '\0')
>>         lang = "und";
>> diff --git a/libavformat/isom.h b/libavformat/isom.h
>> index 41a9c64c11..9d018ebf1f 100644
>> --- a/libavformat/isom.h
>> +++ b/libavformat/isom.h
>> @@ -43,7 +43,7 @@ extern const AVCodecTag ff_codec_movaudio_tags[];
>> extern const AVCodecTag ff_codec_movsubtitle_tags[];
>> extern const AVCodecTag ff_codec_movdata_tags[];
>> 
>> -int ff_mov_iso639_to_lang(const char lang[4], int mp4);
>> +int ff_mov_iso639_to_lang(const char lang[4], int mp4, int
>> strict_std_compliance);
>> int ff_mov_lang_to_iso639(unsigned code, char to[4]);
>> 
>> struct AVAESCTR;
>> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
>> index 520aaafb74..4d7a98245e 100644
>> --- a/libavformat/movenc.c
>> +++ b/libavformat/movenc.c
>> @@ -3429,7 +3429,7 @@ static int mov_write_string_data_tag(AVIOContext
>> *pb, const char *data, int lang
>>         return size;
>>     } else {
>>         if (!lang)
>> -            lang = ff_mov_iso639_to_lang("und", 1);
>> +            lang = ff_mov_iso639_to_lang("und", 1, FF_COMPLIANCE_NORMAL);
>>         avio_wb16(pb, strlen(data)); /* string length */
>>         avio_wb16(pb, lang);
>>         avio_write(pb, data, strlen(data));
>> @@ -3468,7 +3468,7 @@ static AVDictionaryEntry
>> *get_metadata_lang(AVFormatContext *s,
>>     while ((t2 = av_dict_get(s->metadata, tag2, t2,
>> AV_DICT_IGNORE_SUFFIX))) {
>>         len2 = strlen(t2->key);
>>         if (len2 == len + 4 && !strcmp(t->value, t2->value)
>> -            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
>> +            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1,
>> s->strict_std_compliance)) >= 0) {
>>             *lang = l;
>>             return t;
>>         }
>> @@ -6445,7 +6445,7 @@ static int mov_init(AVFormatContext *s)
>> 
>>         track->st  = st;
>>         track->par = st->codecpar;
>> -        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und",
>> mov->mode!=MODE_MOV);
>> +        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und",
>> mov->mode!=MODE_MOV, s->strict_std_compliance);
>>         if (track->language < 0)
>>             track->language = 32767;  // Unspecified Macintosh language
>> code
>>         track->mode = mov->mode;
>> diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
>> index 7a721d7c95..a85cc1a07d 100644
>> --- a/tests/fate/mov.mak
>> +++ b/tests/fate/mov.mak
>> @@ -29,6 +29,7 @@ FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \
>>                    fate-mov-guess-delay-2 \
>>                    fate-mov-guess-delay-3 \
>>                    fate-mov-mp4-with-mov-in24-ver \
>> +                   fate-mov-iso639-lang \
>> 
>> FATE_MOV_FASTSTART = fate-mov-faststart-4gb-overflow \
>> 
>> @@ -124,3 +125,5 @@ fate-mov-faststart-4gb-overflow: CMP = oneline
>> fate-mov-faststart-4gb-overflow: REF = bc875921f151871e787c4b4023269b29
>> 
>> fate-mov-mp4-with-mov-in24-ver: CMD = run ffprobe$(PROGSSUF)$(EXESUF)
>> -show_entries stream=codec_name -select_streams 1
>> $(TARGET_SAMPLES)/mov/mp4-with-mov-in24-ver.mp4
>> +
>> +fate-mov-iso639-lang: CMD = ffmpeg$(PROGSSUF)$(EXESUF) -f lavfi -i
>> sine=frequency=1000:duration=15 -strict experimental -metadata:s:a:0
>> language=deu -y $(TARGET_PATH)/metadata.mov; run ffprobe -show_entries
>> stream=index:stream_tags=language $(TARGET_PATH)/metadata.mov; rm
>> metadata.mov
>> diff --git a/tests/ref/fate/mov-iso639-lang
>> b/tests/ref/fate/mov-iso639-lang
>> new file mode 100644
>> index 0000000000..6d1f61169d
>> --- /dev/null
>> +++ b/tests/ref/fate/mov-iso639-lang
>> @@ -0,0 +1,4 @@
>> +[STREAM]
>> +index=0
>> +TAG:language=deu
>> +[/STREAM]
>> --
>> 2.27.0.111.gc72c7da667-goog
>> 
>> Dear FFmpeg Developers,
> 
> Could you please review this patch when you have time. Thanks.
> 
> Best,
> Yongle


Is it allowed by an official spec ? What would be the reason to use these codes in mov ?

Thanks a lot! 

— 
Baptiste
Yongle Lin July 7, 2020, 5:41 p.m. UTC | #3
On Mon, Jul 6, 2020 at 3:23 PM Baptiste Coudurier <
baptiste.coudurier@gmail.com> wrote:

> Hi Yongle, I hope you are doing well
>
> > On Jul 6, 2020, at 11:04 AM, Yongle Lin <yongle.lin.94@gmail.com> wrote:
> >
> > On Fri, Jun 19, 2020 at 5:11 PM Yongle Lin <yongle.lin.94@gmail.com
> <mailto:yongle.lin.94@gmail.com>> wrote:
> >
> >> Allow ISO 639 language codes for text tracks in mov format when
> >> strictness is set to experimental
> >> ---
> >> libavformat/isom.c             | 9 +++++++--
> >> libavformat/isom.h             | 2 +-
> >> libavformat/movenc.c           | 6 +++---
> >> tests/fate/mov.mak             | 3 +++
> >> tests/ref/fate/mov-iso639-lang | 4 ++++
> >> 5 files changed, 18 insertions(+), 6 deletions(-)
> >> create mode 100644 tests/ref/fate/mov-iso639-lang
> >>
> >> diff --git a/libavformat/isom.c b/libavformat/isom.c
> >> index 44c7b13038..de20ea8d8b 100644
> >> --- a/libavformat/isom.c
> >> +++ b/libavformat/isom.c
> >> @@ -416,7 +416,7 @@ static const char mov_mdhd_language_map[][4] = {
> >>     "cat", "lat", "que", "grn", "aym", "tat", "uig", "dzo", "jav"
> >> };
> >>
> >> -int ff_mov_iso639_to_lang(const char lang[4], int mp4)
> >> +int ff_mov_iso639_to_lang(const char lang[4], int mp4, int
> >> strict_std_compliance)
> >> {
> >>     int i, code = 0;
> >>
> >> @@ -426,8 +426,13 @@ int ff_mov_iso639_to_lang(const char lang[4], int
> mp4)
> >>             return i;
> >>     }
> >>     /* XXX:can we do that in mov too? */
> >> -    if (!mp4)
> >> +    if (!mp4 && (strict_std_compliance != FF_COMPLIANCE_EXPERIMENTAL ||
> >> !strcmp(lang, "und"))) {
> >> +        if (strcmp(lang, "und"))
> >> +            av_log(NULL, AV_LOG_WARNING, "Non macintosh language is
> >> discarded for mov\n");
> >>         return -1;
> >> +    }
> >> +    if (!mp4)
> >> +        av_log(NULL, AV_LOG_WARNING, "Experimental behavior: enable iso
> >> 639 language in mov\n");
> >>     /* handle undefined as such */
> >>     if (lang[0] == '\0')
> >>         lang = "und";
> >> diff --git a/libavformat/isom.h b/libavformat/isom.h
> >> index 41a9c64c11..9d018ebf1f 100644
> >> --- a/libavformat/isom.h
> >> +++ b/libavformat/isom.h
> >> @@ -43,7 +43,7 @@ extern const AVCodecTag ff_codec_movaudio_tags[];
> >> extern const AVCodecTag ff_codec_movsubtitle_tags[];
> >> extern const AVCodecTag ff_codec_movdata_tags[];
> >>
> >> -int ff_mov_iso639_to_lang(const char lang[4], int mp4);
> >> +int ff_mov_iso639_to_lang(const char lang[4], int mp4, int
> >> strict_std_compliance);
> >> int ff_mov_lang_to_iso639(unsigned code, char to[4]);
> >>
> >> struct AVAESCTR;
> >> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> >> index 520aaafb74..4d7a98245e 100644
> >> --- a/libavformat/movenc.c
> >> +++ b/libavformat/movenc.c
> >> @@ -3429,7 +3429,7 @@ static int mov_write_string_data_tag(AVIOContext
> >> *pb, const char *data, int lang
> >>         return size;
> >>     } else {
> >>         if (!lang)
> >> -            lang = ff_mov_iso639_to_lang("und", 1);
> >> +            lang = ff_mov_iso639_to_lang("und", 1,
> FF_COMPLIANCE_NORMAL);
> >>         avio_wb16(pb, strlen(data)); /* string length */
> >>         avio_wb16(pb, lang);
> >>         avio_write(pb, data, strlen(data));
> >> @@ -3468,7 +3468,7 @@ static AVDictionaryEntry
> >> *get_metadata_lang(AVFormatContext *s,
> >>     while ((t2 = av_dict_get(s->metadata, tag2, t2,
> >> AV_DICT_IGNORE_SUFFIX))) {
> >>         len2 = strlen(t2->key);
> >>         if (len2 == len + 4 && !strcmp(t->value, t2->value)
> >> -            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >=
> 0) {
> >> +            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1,
> >> s->strict_std_compliance)) >= 0) {
> >>             *lang = l;
> >>             return t;
> >>         }
> >> @@ -6445,7 +6445,7 @@ static int mov_init(AVFormatContext *s)
> >>
> >>         track->st  = st;
> >>         track->par = st->codecpar;
> >> -        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und",
> >> mov->mode!=MODE_MOV);
> >> +        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und",
> >> mov->mode!=MODE_MOV, s->strict_std_compliance);
> >>         if (track->language < 0)
> >>             track->language = 32767;  // Unspecified Macintosh language
> >> code
> >>         track->mode = mov->mode;
> >> diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
> >> index 7a721d7c95..a85cc1a07d 100644
> >> --- a/tests/fate/mov.mak
> >> +++ b/tests/fate/mov.mak
> >> @@ -29,6 +29,7 @@ FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \
> >>                    fate-mov-guess-delay-2 \
> >>                    fate-mov-guess-delay-3 \
> >>                    fate-mov-mp4-with-mov-in24-ver \
> >> +                   fate-mov-iso639-lang \
> >>
> >> FATE_MOV_FASTSTART = fate-mov-faststart-4gb-overflow \
> >>
> >> @@ -124,3 +125,5 @@ fate-mov-faststart-4gb-overflow: CMP = oneline
> >> fate-mov-faststart-4gb-overflow: REF = bc875921f151871e787c4b4023269b29
> >>
> >> fate-mov-mp4-with-mov-in24-ver: CMD = run ffprobe$(PROGSSUF)$(EXESUF)
> >> -show_entries stream=codec_name -select_streams 1
> >> $(TARGET_SAMPLES)/mov/mp4-with-mov-in24-ver.mp4
> >> +
> >> +fate-mov-iso639-lang: CMD = ffmpeg$(PROGSSUF)$(EXESUF) -f lavfi -i
> >> sine=frequency=1000:duration=15 -strict experimental -metadata:s:a:0
> >> language=deu -y $(TARGET_PATH)/metadata.mov; run ffprobe -show_entries
> >> stream=index:stream_tags=language $(TARGET_PATH)/metadata.mov; rm
> >> metadata.mov
> >> diff --git a/tests/ref/fate/mov-iso639-lang
> >> b/tests/ref/fate/mov-iso639-lang
> >> new file mode 100644
> >> index 0000000000..6d1f61169d
> >> --- /dev/null
> >> +++ b/tests/ref/fate/mov-iso639-lang
> >> @@ -0,0 +1,4 @@
> >> +[STREAM]
> >> +index=0
> >> +TAG:language=deu
> >> +[/STREAM]
> >> --
> >> 2.27.0.111.gc72c7da667-goog
> >>
> >> Dear FFmpeg Developers,
> >
> > Could you please review this patch when you have time. Thanks.
> >
> > Best,
> > Yongle
>
>
> Is it allowed by an official spec ? What would be the reason to use these
> codes in mov ?
>
> Thanks a lot!
>
> —
> Baptiste
> _______________________________________________
> 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".


Hi Baptiste,

Thank you for your email. Basically, ISO language can be used only for user
data text in a QuickTime file. All other elements including text tracks
must be specified using Macintosh language codes. But it's valid to have
ISO codes for text tracks of mov. So this patch allows ISO 639 codes for
mov files. For example, "-metadata language:s:0 language=deu" currently
drops the language information. I also added a sample FATE test you can
check.

Best,
Yongle
Baptiste Coudurier July 8, 2020, 12:21 a.m. UTC | #4
Hey Yongle,

> On Jul 7, 2020, at 10:41 AM, Yongle Lin <yongle.lin.94@gmail.com> wrote:
> 
> On Mon, Jul 6, 2020 at 3:23 PM Baptiste Coudurier <
> baptiste.coudurier@gmail.com> wrote:
> 
>> Hi Yongle, I hope you are doing well
>> 
>>> On Jul 6, 2020, at 11:04 AM, Yongle Lin <yongle.lin.94@gmail.com> wrote:
>>> 
>>> On Fri, Jun 19, 2020 at 5:11 PM Yongle Lin <yongle.lin.94@gmail.com
>> <mailto:yongle.lin.94@gmail.com>> wrote:
>>> 
>>>> Allow ISO 639 language codes for text tracks in mov format when
>>>> strictness is set to experimental
>>>> ---
>>>> libavformat/isom.c             | 9 +++++++--
>>>> libavformat/isom.h             | 2 +-
>>>> libavformat/movenc.c           | 6 +++---
>>>> tests/fate/mov.mak             | 3 +++
>>>> tests/ref/fate/mov-iso639-lang | 4 ++++
>>>> 5 files changed, 18 insertions(+), 6 deletions(-)
>>>> create mode 100644 tests/ref/fate/mov-iso639-lang
>>>> 
>>>> diff --git a/libavformat/isom.c b/libavformat/isom.c
>>>> index 44c7b13038..de20ea8d8b 100644
>>>> --- a/libavformat/isom.c
>>>> +++ b/libavformat/isom.c
>>>> @@ -416,7 +416,7 @@ static const char mov_mdhd_language_map[][4] = {
>>>>    "cat", "lat", "que", "grn", "aym", "tat", "uig", "dzo", "jav"
>>>> };
>>>> 
>>>> -int ff_mov_iso639_to_lang(const char lang[4], int mp4)
>>>> +int ff_mov_iso639_to_lang(const char lang[4], int mp4, int
>>>> strict_std_compliance)
>>>> {
>>>>    int i, code = 0;
>>>> 
>>>> @@ -426,8 +426,13 @@ int ff_mov_iso639_to_lang(const char lang[4], int
>> mp4)
>>>>            return i;
>>>>    }
>>>>    /* XXX:can we do that in mov too? */
>>>> -    if (!mp4)
>>>> +    if (!mp4 && (strict_std_compliance != FF_COMPLIANCE_EXPERIMENTAL ||
>>>> !strcmp(lang, "und"))) {
>>>> +        if (strcmp(lang, "und"))
>>>> +            av_log(NULL, AV_LOG_WARNING, "Non macintosh language is
>>>> discarded for mov\n");
>>>>        return -1;
>>>> +    }
>>>> +    if (!mp4)
>>>> +        av_log(NULL, AV_LOG_WARNING, "Experimental behavior: enable iso
>>>> 639 language in mov\n");
>>>>    /* handle undefined as such */
>>>>    if (lang[0] == '\0')
>>>>        lang = "und";
>>>> diff --git a/libavformat/isom.h b/libavformat/isom.h
>>>> index 41a9c64c11..9d018ebf1f 100644
>>>> --- a/libavformat/isom.h
>>>> +++ b/libavformat/isom.h
>>>> @@ -43,7 +43,7 @@ extern const AVCodecTag ff_codec_movaudio_tags[];
>>>> extern const AVCodecTag ff_codec_movsubtitle_tags[];
>>>> extern const AVCodecTag ff_codec_movdata_tags[];
>>>> 
>>>> -int ff_mov_iso639_to_lang(const char lang[4], int mp4);
>>>> +int ff_mov_iso639_to_lang(const char lang[4], int mp4, int
>>>> strict_std_compliance);
>>>> int ff_mov_lang_to_iso639(unsigned code, char to[4]);
>>>> 
>>>> struct AVAESCTR;
>>>> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
>>>> index 520aaafb74..4d7a98245e 100644
>>>> --- a/libavformat/movenc.c
>>>> +++ b/libavformat/movenc.c
>>>> @@ -3429,7 +3429,7 @@ static int mov_write_string_data_tag(AVIOContext
>>>> *pb, const char *data, int lang
>>>>        return size;
>>>>    } else {
>>>>        if (!lang)
>>>> -            lang = ff_mov_iso639_to_lang("und", 1);
>>>> +            lang = ff_mov_iso639_to_lang("und", 1,
>> FF_COMPLIANCE_NORMAL);
>>>>        avio_wb16(pb, strlen(data)); /* string length */
>>>>        avio_wb16(pb, lang);
>>>>        avio_write(pb, data, strlen(data));
>>>> @@ -3468,7 +3468,7 @@ static AVDictionaryEntry
>>>> *get_metadata_lang(AVFormatContext *s,
>>>>    while ((t2 = av_dict_get(s->metadata, tag2, t2,
>>>> AV_DICT_IGNORE_SUFFIX))) {
>>>>        len2 = strlen(t2->key);
>>>>        if (len2 == len + 4 && !strcmp(t->value, t2->value)
>>>> -            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >=
>> 0) {
>>>> +            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1,
>>>> s->strict_std_compliance)) >= 0) {
>>>>            *lang = l;
>>>>            return t;
>>>>        }
>>>> @@ -6445,7 +6445,7 @@ static int mov_init(AVFormatContext *s)
>>>> 
>>>>        track->st  = st;
>>>>        track->par = st->codecpar;
>>>> -        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und",
>>>> mov->mode!=MODE_MOV);
>>>> +        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und",
>>>> mov->mode!=MODE_MOV, s->strict_std_compliance);
>>>>        if (track->language < 0)
>>>>            track->language = 32767;  // Unspecified Macintosh language
>>>> code
>>>>        track->mode = mov->mode;
>>>> diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
>>>> index 7a721d7c95..a85cc1a07d 100644
>>>> --- a/tests/fate/mov.mak
>>>> +++ b/tests/fate/mov.mak
>>>> @@ -29,6 +29,7 @@ FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \
>>>>                   fate-mov-guess-delay-2 \
>>>>                   fate-mov-guess-delay-3 \
>>>>                   fate-mov-mp4-with-mov-in24-ver \
>>>> +                   fate-mov-iso639-lang \
>>>> 
>>>> FATE_MOV_FASTSTART = fate-mov-faststart-4gb-overflow \
>>>> 
>>>> @@ -124,3 +125,5 @@ fate-mov-faststart-4gb-overflow: CMP = oneline
>>>> fate-mov-faststart-4gb-overflow: REF = bc875921f151871e787c4b4023269b29
>>>> 
>>>> fate-mov-mp4-with-mov-in24-ver: CMD = run ffprobe$(PROGSSUF)$(EXESUF)
>>>> -show_entries stream=codec_name -select_streams 1
>>>> $(TARGET_SAMPLES)/mov/mp4-with-mov-in24-ver.mp4
>>>> +
>>>> +fate-mov-iso639-lang: CMD = ffmpeg$(PROGSSUF)$(EXESUF) -f lavfi -i
>>>> sine=frequency=1000:duration=15 -strict experimental -metadata:s:a:0
>>>> language=deu -y $(TARGET_PATH)/metadata.mov; run ffprobe -show_entries
>>>> stream=index:stream_tags=language $(TARGET_PATH)/metadata.mov; rm
>>>> metadata.mov
>>>> diff --git a/tests/ref/fate/mov-iso639-lang
>>>> b/tests/ref/fate/mov-iso639-lang
>>>> new file mode 100644
>>>> index 0000000000..6d1f61169d
>>>> --- /dev/null
>>>> +++ b/tests/ref/fate/mov-iso639-lang
>>>> @@ -0,0 +1,4 @@
>>>> +[STREAM]
>>>> +index=0
>>>> +TAG:language=deu
>>>> +[/STREAM]
>>>> --
>>>> 2.27.0.111.gc72c7da667-goog
>>>> 
>>>> Dear FFmpeg Developers,
>>> 
>>> Could you please review this patch when you have time. Thanks.
>>> 
>>> Best,
>>> Yongle
>> 
>> 
>> Is it allowed by an official spec ? What would be the reason to use these
>> codes in mov ?
>> 
>> Thanks a lot!
>> 
>> —
>> Baptiste
>> _______________________________________________
>> 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".
> 
> 
> Hi Baptiste,
> 
> Thank you for your email. Basically, ISO language can be used only for user
> data text in a QuickTime file. All other elements including text tracks
> must be specified using Macintosh language codes. But it's valid to have
> ISO codes for text tracks of mov. So this patch allows ISO 639 codes for
> mov files. For example, "-metadata language:s:0 language=deu" currently
> drops the language information. I also added a sample FATE test you can
> check.


"Note: ISO language codes cannot be used for all elements of a QuickTime file. Currently, ISO language codes can be used only for user data text. All other elements, including text tracks, must be specified using Macintosh language codes.”

I think “user data text” is the user data contained in “meta” boxes. I’m not sure this patch actually implements that.

Thanks!

— 
Baptiste Coudurier
diff mbox series

Patch

diff --git a/libavformat/isom.c b/libavformat/isom.c
index 44c7b13038..de20ea8d8b 100644
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -416,7 +416,7 @@  static const char mov_mdhd_language_map[][4] = {
     "cat", "lat", "que", "grn", "aym", "tat", "uig", "dzo", "jav"
 };
 
-int ff_mov_iso639_to_lang(const char lang[4], int mp4)
+int ff_mov_iso639_to_lang(const char lang[4], int mp4, int strict_std_compliance)
 {
     int i, code = 0;
 
@@ -426,8 +426,13 @@  int ff_mov_iso639_to_lang(const char lang[4], int mp4)
             return i;
     }
     /* XXX:can we do that in mov too? */
-    if (!mp4)
+    if (!mp4 && (strict_std_compliance != FF_COMPLIANCE_EXPERIMENTAL || !strcmp(lang, "und"))) {
+        if (strcmp(lang, "und"))
+            av_log(NULL, AV_LOG_WARNING, "Non macintosh language is discarded for mov\n");
         return -1;
+    }
+    if (!mp4)
+        av_log(NULL, AV_LOG_WARNING, "Experimental behavior: enable iso 639 language in mov\n");
     /* handle undefined as such */
     if (lang[0] == '\0')
         lang = "und";
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 41a9c64c11..9d018ebf1f 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -43,7 +43,7 @@  extern const AVCodecTag ff_codec_movaudio_tags[];
 extern const AVCodecTag ff_codec_movsubtitle_tags[];
 extern const AVCodecTag ff_codec_movdata_tags[];
 
-int ff_mov_iso639_to_lang(const char lang[4], int mp4);
+int ff_mov_iso639_to_lang(const char lang[4], int mp4, int strict_std_compliance);
 int ff_mov_lang_to_iso639(unsigned code, char to[4]);
 
 struct AVAESCTR;
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 520aaafb74..4d7a98245e 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -3429,7 +3429,7 @@  static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang
         return size;
     } else {
         if (!lang)
-            lang = ff_mov_iso639_to_lang("und", 1);
+            lang = ff_mov_iso639_to_lang("und", 1, FF_COMPLIANCE_NORMAL);
         avio_wb16(pb, strlen(data)); /* string length */
         avio_wb16(pb, lang);
         avio_write(pb, data, strlen(data));
@@ -3468,7 +3468,7 @@  static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
     while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
         len2 = strlen(t2->key);
         if (len2 == len + 4 && !strcmp(t->value, t2->value)
-            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
+            && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1, s->strict_std_compliance)) >= 0) {
             *lang = l;
             return t;
         }
@@ -6445,7 +6445,7 @@  static int mov_init(AVFormatContext *s)
 
         track->st  = st;
         track->par = st->codecpar;
-        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
+        track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV, s->strict_std_compliance);
         if (track->language < 0)
             track->language = 32767;  // Unspecified Macintosh language code
         track->mode = mov->mode;
diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak
index 7a721d7c95..a85cc1a07d 100644
--- a/tests/fate/mov.mak
+++ b/tests/fate/mov.mak
@@ -29,6 +29,7 @@  FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \
                    fate-mov-guess-delay-2 \
                    fate-mov-guess-delay-3 \
                    fate-mov-mp4-with-mov-in24-ver \
+                   fate-mov-iso639-lang \
 
 FATE_MOV_FASTSTART = fate-mov-faststart-4gb-overflow \
 
@@ -124,3 +125,5 @@  fate-mov-faststart-4gb-overflow: CMP = oneline
 fate-mov-faststart-4gb-overflow: REF = bc875921f151871e787c4b4023269b29
 
 fate-mov-mp4-with-mov-in24-ver: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=codec_name -select_streams 1 $(TARGET_SAMPLES)/mov/mp4-with-mov-in24-ver.mp4
+
+fate-mov-iso639-lang: CMD = ffmpeg$(PROGSSUF)$(EXESUF) -f lavfi -i sine=frequency=1000:duration=15 -strict experimental -metadata:s:a:0 language=deu -y $(TARGET_PATH)/metadata.mov; run ffprobe -show_entries stream=index:stream_tags=language $(TARGET_PATH)/metadata.mov; rm metadata.mov
diff --git a/tests/ref/fate/mov-iso639-lang b/tests/ref/fate/mov-iso639-lang
new file mode 100644
index 0000000000..6d1f61169d
--- /dev/null
+++ b/tests/ref/fate/mov-iso639-lang
@@ -0,0 +1,4 @@ 
+[STREAM]
+index=0
+TAG:language=deu
+[/STREAM]