diff mbox

[FFmpeg-devel,1/3] avformat/avienc: write chained master index only if std_compliance is normal or below

Message ID 1483952212-26754-1-git-send-email-t.rapp@noa-archive.com
State Superseded
Headers show

Commit Message

Tobias Rapp Jan. 9, 2017, 8:56 a.m. UTC
OpenDML specification v1.02 states that entries of a master index chunk
shall point to standard or field index chunks.

Changed incorrect duration of last master index entry to -1 in case it
points to another master index.

Propagate error when index write fails.

Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
---
 libavformat/avienc.c | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

Comments

Michael Niedermayer Jan. 9, 2017, 11:19 p.m. UTC | #1
On Mon, Jan 09, 2017 at 09:56:50AM +0100, Tobias Rapp wrote:
> OpenDML specification v1.02 states that entries of a master index chunk
> shall point to standard or field index chunks.
> 
> Changed incorrect duration of last master index entry to -1 in case it
> points to another master index.
> 
> Propagate error when index write fails.
> 
> Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
> ---
>  libavformat/avienc.c | 30 +++++++++++++++++++++++-------
>  1 file changed, 23 insertions(+), 7 deletions(-)
> 
> diff --git a/libavformat/avienc.c b/libavformat/avienc.c
> index fd16fff..5d5c02a 100644
> --- a/libavformat/avienc.c
> +++ b/libavformat/avienc.c
> @@ -524,7 +524,13 @@ static int avi_write_header(AVFormatContext *s)
>      return 0;
>  }
>  
> -static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size)
> +/* Index entry points to standard index */
> +#define AVI_UPDATE_ODML_ENTRY_DEFAULT   0x00000000
> +
> +/* Index entry points to another master index */
> +#define AVI_UPDATE_ODML_ENTRY_MASTER    0x00000001
> +
> +static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size, int flags)
>  {
>      AVIOContext *pb = s->pb;
>      AVIContext *avi = s->priv_data;
> @@ -544,7 +550,10 @@ static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix,
>      avio_wl64(pb, ix);                    /* qwOffset */
>      avio_wl32(pb, size);                  /* dwSize */
>      ff_parse_specific_params(s->streams[stream_index], &au_byterate, &au_ssize, &au_scale);
> -    if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
> +    if (flags & AVI_UPDATE_ODML_ENTRY_MASTER) {
> +        av_assert0(s->strict_std_compliance <= FF_COMPLIANCE_NORMAL);
> +        avio_wl32(pb, -1);  /* dwDuration (undefined) */
> +    } else if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
>          uint32_t audio_segm_size = (avist->audio_strm_length - avist->indexes.audio_strm_offset);
>          if ((audio_segm_size % au_ssize > 0) && !avist->sample_requested) {
>              avpriv_request_sample(s, "OpenDML index duration for audio packets with partial frames");

> @@ -567,6 +576,12 @@ static int avi_write_ix(AVFormatContext *s)
>  
>      av_assert0(pb->seekable);
>  
> +    if (avi->riff_id >= AVI_MASTER_INDEX_SIZE && s->strict_std_compliance > FF_COMPLIANCE_NORMAL) {
> +        av_log(s, AV_LOG_ERROR, "Invalid riff index %d >= %d\n",
> +               avi->riff_id, AVI_MASTER_INDEX_SIZE);
> +        return AVERROR(EINVAL);
> +    }

isnt it better to warn the user and inform him at the end what size
of reserved space would have been needed?

not saying iam against this, i do see how it is formally correct to
fail hard but it feels painfull to me to fail
muxing at 256gb hard when we can perfectly fine just continue and
the user can just remux the file with bigger reserved master index
to fix it




[...]
Tobias Rapp Jan. 10, 2017, 8:26 a.m. UTC | #2
On 10.01.2017 00:19, Michael Niedermayer wrote:
> On Mon, Jan 09, 2017 at 09:56:50AM +0100, Tobias Rapp wrote:
>> OpenDML specification v1.02 states that entries of a master index chunk
>> shall point to standard or field index chunks.
>>
>> Changed incorrect duration of last master index entry to -1 in case it
>> points to another master index.
>>
>> Propagate error when index write fails.
>>
>> Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
>> ---
>>  libavformat/avienc.c | 30 +++++++++++++++++++++++-------
>>  1 file changed, 23 insertions(+), 7 deletions(-)
>>
>> diff --git a/libavformat/avienc.c b/libavformat/avienc.c
>> index fd16fff..5d5c02a 100644
>> --- a/libavformat/avienc.c
>> +++ b/libavformat/avienc.c
>> @@ -524,7 +524,13 @@ static int avi_write_header(AVFormatContext *s)
>>      return 0;
>>  }
>>
>> -static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size)
>> +/* Index entry points to standard index */
>> +#define AVI_UPDATE_ODML_ENTRY_DEFAULT   0x00000000
>> +
>> +/* Index entry points to another master index */
>> +#define AVI_UPDATE_ODML_ENTRY_MASTER    0x00000001
>> +
>> +static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size, int flags)
>>  {
>>      AVIOContext *pb = s->pb;
>>      AVIContext *avi = s->priv_data;
>> @@ -544,7 +550,10 @@ static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix,
>>      avio_wl64(pb, ix);                    /* qwOffset */
>>      avio_wl32(pb, size);                  /* dwSize */
>>      ff_parse_specific_params(s->streams[stream_index], &au_byterate, &au_ssize, &au_scale);
>> -    if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
>> +    if (flags & AVI_UPDATE_ODML_ENTRY_MASTER) {
>> +        av_assert0(s->strict_std_compliance <= FF_COMPLIANCE_NORMAL);
>> +        avio_wl32(pb, -1);  /* dwDuration (undefined) */
>> +    } else if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
>>          uint32_t audio_segm_size = (avist->audio_strm_length - avist->indexes.audio_strm_offset);
>>          if ((audio_segm_size % au_ssize > 0) && !avist->sample_requested) {
>>              avpriv_request_sample(s, "OpenDML index duration for audio packets with partial frames");
>
>> @@ -567,6 +576,12 @@ static int avi_write_ix(AVFormatContext *s)
>>
>>      av_assert0(pb->seekable);
>>
>> +    if (avi->riff_id >= AVI_MASTER_INDEX_SIZE && s->strict_std_compliance > FF_COMPLIANCE_NORMAL) {
>> +        av_log(s, AV_LOG_ERROR, "Invalid riff index %d >= %d\n",
>> +               avi->riff_id, AVI_MASTER_INDEX_SIZE);
>> +        return AVERROR(EINVAL);
>> +    }
>
> isnt it better to warn the user and inform him at the end what size
> of reserved space would have been needed?
>
> not saying iam against this, i do see how it is formally correct to
> fail hard but it feels painfull to me to fail
> muxing at 256gb hard when we can perfectly fine just continue and
> the user can just remux the file with bigger reserved master index
> to fix it

But then adding "-strict strict" just enables a warning message and a 
non-compliant file is written still? Or do you mean that additionally a 
warning message could be written in case std_compliance is <= normal?

Background story: I'm working on an application that fetches some AVI 
file byte range from tape storage and restores the file header. The 
header restoration requires the ODML master index in the header to be 
complete. Thus I'd like to ensure that all AVI files put into the 
archive have a compliant/compatible index structure.

For such automated processes failing hard is more safe than continuing 
with a warning message, checking for log messages in the host 
application and possibly re-running the transcoding with adapted options.

Regards,
Tobias
Michael Niedermayer Jan. 13, 2017, 4:42 p.m. UTC | #3
On Tue, Jan 10, 2017 at 09:26:53AM +0100, Tobias Rapp wrote:
> On 10.01.2017 00:19, Michael Niedermayer wrote:
> >On Mon, Jan 09, 2017 at 09:56:50AM +0100, Tobias Rapp wrote:
> >>OpenDML specification v1.02 states that entries of a master index chunk
> >>shall point to standard or field index chunks.
> >>
> >>Changed incorrect duration of last master index entry to -1 in case it
> >>points to another master index.
> >>
> >>Propagate error when index write fails.
> >>
> >>Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
> >>---
> >> libavformat/avienc.c | 30 +++++++++++++++++++++++-------
> >> 1 file changed, 23 insertions(+), 7 deletions(-)
> >>
> >>diff --git a/libavformat/avienc.c b/libavformat/avienc.c
> >>index fd16fff..5d5c02a 100644
> >>--- a/libavformat/avienc.c
> >>+++ b/libavformat/avienc.c
> >>@@ -524,7 +524,13 @@ static int avi_write_header(AVFormatContext *s)
> >>     return 0;
> >> }
> >>
> >>-static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size)
> >>+/* Index entry points to standard index */
> >>+#define AVI_UPDATE_ODML_ENTRY_DEFAULT   0x00000000
> >>+
> >>+/* Index entry points to another master index */
> >>+#define AVI_UPDATE_ODML_ENTRY_MASTER    0x00000001
> >>+
> >>+static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size, int flags)
> >> {
> >>     AVIOContext *pb = s->pb;
> >>     AVIContext *avi = s->priv_data;
> >>@@ -544,7 +550,10 @@ static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix,
> >>     avio_wl64(pb, ix);                    /* qwOffset */
> >>     avio_wl32(pb, size);                  /* dwSize */
> >>     ff_parse_specific_params(s->streams[stream_index], &au_byterate, &au_ssize, &au_scale);
> >>-    if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
> >>+    if (flags & AVI_UPDATE_ODML_ENTRY_MASTER) {
> >>+        av_assert0(s->strict_std_compliance <= FF_COMPLIANCE_NORMAL);
> >>+        avio_wl32(pb, -1);  /* dwDuration (undefined) */
> >>+    } else if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
> >>         uint32_t audio_segm_size = (avist->audio_strm_length - avist->indexes.audio_strm_offset);
> >>         if ((audio_segm_size % au_ssize > 0) && !avist->sample_requested) {
> >>             avpriv_request_sample(s, "OpenDML index duration for audio packets with partial frames");
> >
> >>@@ -567,6 +576,12 @@ static int avi_write_ix(AVFormatContext *s)
> >>
> >>     av_assert0(pb->seekable);
> >>
> >>+    if (avi->riff_id >= AVI_MASTER_INDEX_SIZE && s->strict_std_compliance > FF_COMPLIANCE_NORMAL) {
> >>+        av_log(s, AV_LOG_ERROR, "Invalid riff index %d >= %d\n",
> >>+               avi->riff_id, AVI_MASTER_INDEX_SIZE);
> >>+        return AVERROR(EINVAL);
> >>+    }
> >
> >isnt it better to warn the user and inform him at the end what size
> >of reserved space would have been needed?
> >
> >not saying iam against this, i do see how it is formally correct to
> >fail hard but it feels painfull to me to fail
> >muxing at 256gb hard when we can perfectly fine just continue and
> >the user can just remux the file with bigger reserved master index
> >to fix it
> 
> But then adding "-strict strict" just enables a warning message and
> a non-compliant file is written still? Or do you mean that
> additionally a warning message could be written in case
> std_compliance is <= normal?
> 
> Background story: I'm working on an application that fetches some
> AVI file byte range from tape storage and restores the file header.
> The header restoration requires the ODML master index in the header
> to be complete. Thus I'd like to ensure that all AVI files put into
> the archive have a compliant/compatible index structure.
> 
> For such automated processes failing hard is more safe than
> continuing with a warning message, checking for log messages in the
> host application and possibly re-running the transcoding with
> adapted options.

whats your oppinion on an option that selects muxer error behavior ?
something that can
fail immedeatly on error or
warn but continue, return failure after writing the file and trailer

that is a option to make it possible for a muxer to continue even
if there was an error, maybe even a int max_muxer_error or something
else?


[...]
Tobias Rapp Jan. 17, 2017, 1:39 p.m. UTC | #4
Added suggested output stream duration hinting. Uses output stream duration and
bitrate as a hint for better filesize guessing. If stream bitrate is unknown a
worst-case value is assumed.

Sidenote: Noticed during tests that most loss-less encoders don't set bitrate
and thus the options_table.h default value of 200k is used in avi_write_header.
Not sure whether to fix this per encoder or just clear bitrate somewhere in
avcodec_open2 based on AV_CODEC_PROP_LOSSLESS.


Tobias Rapp (4):
  ffmpeg: pass output stream duration as a hint to the muxer
  avformat/avienc: write chained master index only if std_compliance is
    normal or below
  avformat/avienc: add reserve_index_space option
  doc/muxers: add AVI muxer documentation

 doc/muxers.texi                         |  33 ++++++++++
 ffmpeg.c                                |   9 +++
 libavformat/avformat.h                  |   3 +
 libavformat/avi.h                       |   1 -
 libavformat/avienc.c                    | 108 ++++++++++++++++++++++++++++----
 libavformat/version.h                   |   2 +-
 tests/ref/fate/mpeg4-bsf-unpack-bframes |   2 +-
 tests/ref/lavf-fate/avi_cram            |   2 +-
 8 files changed, 143 insertions(+), 17 deletions(-)
Tobias Rapp Jan. 17, 2017, 1:44 p.m. UTC | #5
On 13.01.2017 17:42, Michael Niedermayer wrote:
> On Tue, Jan 10, 2017 at 09:26:53AM +0100, Tobias Rapp wrote:
>> On 10.01.2017 00:19, Michael Niedermayer wrote:
>>>  [...]
>>> isnt it better to warn the user and inform him at the end what size
>>> of reserved space would have been needed?
>>>
>>> not saying iam against this, i do see how it is formally correct to
>>> fail hard but it feels painfull to me to fail
>>> muxing at 256gb hard when we can perfectly fine just continue and
>>> the user can just remux the file with bigger reserved master index
>>> to fix it
>>
>> But then adding "-strict strict" just enables a warning message and
>> a non-compliant file is written still? Or do you mean that
>> additionally a warning message could be written in case
>> std_compliance is <= normal?
>>
>> Background story: I'm working on an application that fetches some
>> AVI file byte range from tape storage and restores the file header.
>> The header restoration requires the ODML master index in the header
>> to be complete. Thus I'd like to ensure that all AVI files put into
>> the archive have a compliant/compatible index structure.
>>
>> For such automated processes failing hard is more safe than
>> continuing with a warning message, checking for log messages in the
>> host application and possibly re-running the transcoding with
>> adapted options.
>
> whats your oppinion on an option that selects muxer error behavior ?
> something that can
> fail immedeatly on error or
> warn but continue, return failure after writing the file and trailer
>
> that is a option to make it possible for a muxer to continue even
> if there was an error, maybe even a int max_muxer_error or something
> else?

You mean something like extending the current use of error_recognition 
and AV_EF_EXPLODE to encoders/muxers? In general it might be a good idea 
but I don't see how it helps in the current case.

When all entries of the master index are exhausted and another entry is 
to be added the basic options are:
a) write a chained master index (currently implemented)
b) enlarge the master index (currently not implemented and I won't 
volunteer for doing it)
c) fail

(a) slightly violates the specs but (b+c) doesn't. One could see (c) as 
a placeholder until (b) is done. In that case '-strict 1' would perform 
(b) and '-strict -1' might perform (a) because it is faster.

Version 2 of the patch series now adds a compliance warning with proper 
reserve_index_space value to (a).

Regards,
Tobias
Michael Niedermayer Jan. 17, 2017, 6:10 p.m. UTC | #6
On Tue, Jan 17, 2017 at 02:44:28PM +0100, Tobias Rapp wrote:
> On 13.01.2017 17:42, Michael Niedermayer wrote:
> >On Tue, Jan 10, 2017 at 09:26:53AM +0100, Tobias Rapp wrote:
> >>On 10.01.2017 00:19, Michael Niedermayer wrote:
> >>> [...]
> >>>isnt it better to warn the user and inform him at the end what size
> >>>of reserved space would have been needed?
> >>>
> >>>not saying iam against this, i do see how it is formally correct to
> >>>fail hard but it feels painfull to me to fail
> >>>muxing at 256gb hard when we can perfectly fine just continue and
> >>>the user can just remux the file with bigger reserved master index
> >>>to fix it
> >>
> >>But then adding "-strict strict" just enables a warning message and
> >>a non-compliant file is written still? Or do you mean that
> >>additionally a warning message could be written in case
> >>std_compliance is <= normal?
> >>
> >>Background story: I'm working on an application that fetches some
> >>AVI file byte range from tape storage and restores the file header.
> >>The header restoration requires the ODML master index in the header
> >>to be complete. Thus I'd like to ensure that all AVI files put into
> >>the archive have a compliant/compatible index structure.
> >>
> >>For such automated processes failing hard is more safe than
> >>continuing with a warning message, checking for log messages in the
> >>host application and possibly re-running the transcoding with
> >>adapted options.
> >
> >whats your oppinion on an option that selects muxer error behavior ?
> >something that can
> >fail immedeatly on error or
> >warn but continue, return failure after writing the file and trailer
> >
> >that is a option to make it possible for a muxer to continue even
> >if there was an error, maybe even a int max_muxer_error or something
> >else?
> 

> You mean something like extending the current use of
> error_recognition and AV_EF_EXPLODE to encoders/muxers? In general

no, the semantic meaning is different
recogniing errors in the input material and recognizing errors in the
muxer "implementation" in relation to the used input or other are not
the same thing.
They may have different values, different defaults, and would have
different explanation in the docs



> it might be a good idea but I don't see how it helps in the current
> case.

well, it gives the user the option
d) write a working file with chained master index and fail at trailer
writing time to indicate that its not spec compliant but loose no
data. The use case is anything that has non recoverable input,
anything that cannot be re-run with a larger reserved space


> 
> When all entries of the master index are exhausted and another entry
> is to be added the basic options are:
> a) write a chained master index (currently implemented)
> b) enlarge the master index (currently not implemented and I won't
> volunteer for doing it)
> c) fail
>

[...]
Tobias Rapp Jan. 18, 2017, 9:18 a.m. UTC | #7
On 17.01.2017 19:10, Michael Niedermayer wrote:
> On Tue, Jan 17, 2017 at 02:44:28PM +0100, Tobias Rapp wrote:
>> On 13.01.2017 17:42, Michael Niedermayer wrote:
>>> On Tue, Jan 10, 2017 at 09:26:53AM +0100, Tobias Rapp wrote:
>>>> On 10.01.2017 00:19, Michael Niedermayer wrote:
>>>>> [...]
>>>>> isnt it better to warn the user and inform him at the end what size
>>>>> of reserved space would have been needed?
>>>>>
>>>>> not saying iam against this, i do see how it is formally correct to
>>>>> fail hard but it feels painfull to me to fail
>>>>> muxing at 256gb hard when we can perfectly fine just continue and
>>>>> the user can just remux the file with bigger reserved master index
>>>>> to fix it
>>>>
>>>> But then adding "-strict strict" just enables a warning message and
>>>> a non-compliant file is written still? Or do you mean that
>>>> additionally a warning message could be written in case
>>>> std_compliance is <= normal?
>>>>
>>>> Background story: I'm working on an application that fetches some
>>>> AVI file byte range from tape storage and restores the file header.
>>>> The header restoration requires the ODML master index in the header
>>>> to be complete. Thus I'd like to ensure that all AVI files put into
>>>> the archive have a compliant/compatible index structure.
>>>>
>>>> For such automated processes failing hard is more safe than
>>>> continuing with a warning message, checking for log messages in the
>>>> host application and possibly re-running the transcoding with
>>>> adapted options.
>>>
>>> whats your oppinion on an option that selects muxer error behavior ?
>>> something that can
>>> fail immedeatly on error or
>>> warn but continue, return failure after writing the file and trailer
>>>
>>> that is a option to make it possible for a muxer to continue even
>>> if there was an error, maybe even a int max_muxer_error or something
>>> else?
>>
>
>> You mean something like extending the current use of
>> error_recognition and AV_EF_EXPLODE to encoders/muxers? In general
>
> no, the semantic meaning is different
> recogniing errors in the input material and recognizing errors in the
> muxer "implementation" in relation to the used input or other are not
> the same thing.
> They may have different values, different defaults, and would have
> different explanation in the docs
>
>> it might be a good idea but I don't see how it helps in the current
>> case.
>
> well, it gives the user the option
> d) write a working file with chained master index and fail at trailer
> writing time to indicate that its not spec compliant but loose no
> data. The use case is anything that has non recoverable input,
> anything that cannot be re-run with a larger reserved space

I agree this would be better e.g. when recording live data coming from 
an input device. Would the indication be done by some special return 
code "AV_PROBLEM_BUT_CONTINUE" on API level? Or maybe a separate error 
reporting field/buffer within the AVFormatContext struct? Trying to 
understand how it would integrate into the host application 
(ffmpeg/other) ...

Anyway, will send version 3 of the patch series with this patch excluded.

> [...]

Regards,
Tobias
Michael Niedermayer Jan. 19, 2017, 12:58 a.m. UTC | #8
On Wed, Jan 18, 2017 at 10:18:36AM +0100, Tobias Rapp wrote:
> On 17.01.2017 19:10, Michael Niedermayer wrote:
> >On Tue, Jan 17, 2017 at 02:44:28PM +0100, Tobias Rapp wrote:
> >>On 13.01.2017 17:42, Michael Niedermayer wrote:
> >>>On Tue, Jan 10, 2017 at 09:26:53AM +0100, Tobias Rapp wrote:
> >>>>On 10.01.2017 00:19, Michael Niedermayer wrote:
> >>>>>[...]
> >>>>>isnt it better to warn the user and inform him at the end what size
> >>>>>of reserved space would have been needed?
> >>>>>
> >>>>>not saying iam against this, i do see how it is formally correct to
> >>>>>fail hard but it feels painfull to me to fail
> >>>>>muxing at 256gb hard when we can perfectly fine just continue and
> >>>>>the user can just remux the file with bigger reserved master index
> >>>>>to fix it
> >>>>
> >>>>But then adding "-strict strict" just enables a warning message and
> >>>>a non-compliant file is written still? Or do you mean that
> >>>>additionally a warning message could be written in case
> >>>>std_compliance is <= normal?
> >>>>
> >>>>Background story: I'm working on an application that fetches some
> >>>>AVI file byte range from tape storage and restores the file header.
> >>>>The header restoration requires the ODML master index in the header
> >>>>to be complete. Thus I'd like to ensure that all AVI files put into
> >>>>the archive have a compliant/compatible index structure.
> >>>>
> >>>>For such automated processes failing hard is more safe than
> >>>>continuing with a warning message, checking for log messages in the
> >>>>host application and possibly re-running the transcoding with
> >>>>adapted options.
> >>>
> >>>whats your oppinion on an option that selects muxer error behavior ?
> >>>something that can
> >>>fail immedeatly on error or
> >>>warn but continue, return failure after writing the file and trailer
> >>>
> >>>that is a option to make it possible for a muxer to continue even
> >>>if there was an error, maybe even a int max_muxer_error or something
> >>>else?
> >>
> >
> >>You mean something like extending the current use of
> >>error_recognition and AV_EF_EXPLODE to encoders/muxers? In general
> >
> >no, the semantic meaning is different
> >recogniing errors in the input material and recognizing errors in the
> >muxer "implementation" in relation to the used input or other are not
> >the same thing.
> >They may have different values, different defaults, and would have
> >different explanation in the docs
> >
> >>it might be a good idea but I don't see how it helps in the current
> >>case.
> >
> >well, it gives the user the option
> >d) write a working file with chained master index and fail at trailer
> >writing time to indicate that its not spec compliant but loose no
> >data. The use case is anything that has non recoverable input,
> >anything that cannot be re-run with a larger reserved space
> 
> I agree this would be better e.g. when recording live data coming
> from an input device. Would the indication be done by some special
> return code "AV_PROBLEM_BUT_CONTINUE" on API level? Or maybe a
> separate error reporting field/buffer within the AVFormatContext
> struct? Trying to understand how it would integrate into the host
> application (ffmpeg/other) ...

what i was thinking about would  when enabled not return an error
before the end, but a AV_PROBLEM_BUT_CONTINUE would be an option too

[...]
diff mbox

Patch

diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index fd16fff..5d5c02a 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -524,7 +524,13 @@  static int avi_write_header(AVFormatContext *s)
     return 0;
 }
 
-static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size)
+/* Index entry points to standard index */
+#define AVI_UPDATE_ODML_ENTRY_DEFAULT   0x00000000
+
+/* Index entry points to another master index */
+#define AVI_UPDATE_ODML_ENTRY_MASTER    0x00000001
+
+static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size, int flags)
 {
     AVIOContext *pb = s->pb;
     AVIContext *avi = s->priv_data;
@@ -544,7 +550,10 @@  static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix,
     avio_wl64(pb, ix);                    /* qwOffset */
     avio_wl32(pb, size);                  /* dwSize */
     ff_parse_specific_params(s->streams[stream_index], &au_byterate, &au_ssize, &au_scale);
-    if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
+    if (flags & AVI_UPDATE_ODML_ENTRY_MASTER) {
+        av_assert0(s->strict_std_compliance <= FF_COMPLIANCE_NORMAL);
+        avio_wl32(pb, -1);  /* dwDuration (undefined) */
+    } else if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
         uint32_t audio_segm_size = (avist->audio_strm_length - avist->indexes.audio_strm_offset);
         if ((audio_segm_size % au_ssize > 0) && !avist->sample_requested) {
             avpriv_request_sample(s, "OpenDML index duration for audio packets with partial frames");
@@ -567,6 +576,12 @@  static int avi_write_ix(AVFormatContext *s)
 
     av_assert0(pb->seekable);
 
+    if (avi->riff_id >= AVI_MASTER_INDEX_SIZE && s->strict_std_compliance > FF_COMPLIANCE_NORMAL) {
+        av_log(s, AV_LOG_ERROR, "Invalid riff index %d >= %d\n",
+               avi->riff_id, AVI_MASTER_INDEX_SIZE);
+        return AVERROR(EINVAL);
+    }
+
     for (i = 0; i < s->nb_streams; i++) {
         AVIStream *avist = s->streams[i]->priv_data;
         if (avi->riff_id - avist->indexes.master_odml_riff_id_base == AVI_MASTER_INDEX_SIZE) {
@@ -574,7 +589,7 @@  static int avi_write_ix(AVFormatContext *s)
             int size = 8+2+1+1+4+8+4+4+16*AVI_MASTER_INDEX_SIZE;
 
             pos = avio_tell(pb);
-            update_odml_entry(s, i, pos, size);
+            update_odml_entry(s, i, pos, size, AVI_UPDATE_ODML_ENTRY_MASTER);
             write_odml_master(s, i);
             av_assert1(avio_tell(pb) - pos == size);
             avist->indexes.master_odml_riff_id_base = avi->riff_id - 1;
@@ -610,7 +625,7 @@  static int avi_write_ix(AVFormatContext *s)
                           (ie->flags & 0x10 ? 0 : 0x80000000));
         }
 
-        update_odml_entry(s, i, ix, avio_tell(pb) - ix);
+        update_odml_entry(s, i, ix, avio_tell(pb) - ix, AVI_UPDATE_ODML_ENTRY_DEFAULT);
     }
     return 0;
 }
@@ -801,6 +816,7 @@  static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
     AVIOContext *pb     = s->pb;
     AVIStream *avist    = s->streams[stream_index]->priv_data;
     AVCodecParameters *par = s->streams[stream_index]->codecpar;
+    int ret;
 
     if (pkt->dts != AV_NOPTS_VALUE)
         avist->last_dts = pkt->dts + pkt->duration;
@@ -810,7 +826,8 @@  static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
     // Make sure to put an OpenDML chunk when the file size exceeds the limits
     if (pb->seekable &&
         (avio_tell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) {
-        avi_write_ix(s);
+        if ((ret = avi_write_ix(s)) < 0)
+            return ret;
         ff_end_tag(pb, avi->movi_list);
 
         if (avi->riff_id == 1)
@@ -827,7 +844,6 @@  static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
         avist->audio_strm_length += size;
 
     if (s->pb->seekable) {
-        int ret;
         ret = avi_add_ientry(s, stream_index, NULL, flags, size);
         if (ret < 0)
             return ret;
@@ -861,7 +877,7 @@  static int avi_write_trailer(AVFormatContext *s)
             res = avi_write_idx1(s);
             ff_end_tag(pb, avi->riff_start);
         } else {
-            avi_write_ix(s);
+            res = avi_write_ix(s);
             ff_end_tag(pb, avi->movi_list);
             ff_end_tag(pb, avi->riff_start);