Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
ffmpeg
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ffmpeg
Commits
55f9037f
Commit
55f9037f
authored
Sep 30, 2012
by
Luca Barbato
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avformat: split muxing functions from util.c
parent
bfcd4b6a
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
580 additions
and
517 deletions
+580
-517
Makefile
libavformat/Makefile
+1
-0
internal.h
libavformat/internal.h
+9
-0
mux.c
libavformat/mux.c
+564
-0
utils.c
libavformat/utils.c
+6
-517
No files found.
libavformat/Makefile
View file @
55f9037f
...
@@ -12,6 +12,7 @@ OBJS = allformats.o \
...
@@ -12,6 +12,7 @@ OBJS = allformats.o \
id3v1.o
\
id3v1.o
\
id3v2.o
\
id3v2.o
\
metadata.o
\
metadata.o
\
mux.o
\
options.o
\
options.o
\
os_support.o
\
os_support.o
\
riff.o
\
riff.o
\
...
...
libavformat/internal.h
View file @
55f9037f
...
@@ -345,4 +345,13 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt);
...
@@ -345,4 +345,13 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt);
int
ff_interleave_packet_per_dts
(
AVFormatContext
*
s
,
AVPacket
*
out
,
int
ff_interleave_packet_per_dts
(
AVFormatContext
*
s
,
AVPacket
*
out
,
AVPacket
*
pkt
,
int
flush
);
AVPacket
*
pkt
,
int
flush
);
/**
* Return the frame duration in seconds. Return 0 if not available.
*/
void
ff_compute_frame_duration
(
int
*
pnum
,
int
*
pden
,
AVStream
*
st
,
AVCodecParserContext
*
pc
,
AVPacket
*
pkt
);
int
ff_get_audio_frame_size
(
AVCodecContext
*
enc
,
int
size
,
int
mux
);
#endif
/* AVFORMAT_INTERNAL_H */
#endif
/* AVFORMAT_INTERNAL_H */
libavformat/mux.c
0 → 100644
View file @
55f9037f
/*
* muxing functions for use within Libav
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* #define DEBUG */
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
#include "libavcodec/internal.h"
#include "libavcodec/bytestream.h"
#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "libavutil/pixdesc.h"
#include "metadata.h"
#include "id3v2.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
#include "libavutil/time.h"
#include "riff.h"
#include "audiointerleave.h"
#include "url.h"
#include <stdarg.h>
#if CONFIG_NETWORK
#include "network.h"
#endif
#undef NDEBUG
#include <assert.h>
/**
* @file
* muxing functions for use within Libav
*/
/* fraction handling */
/**
* f = val + (num / den) + 0.5.
*
* 'num' is normalized so that it is such as 0 <= num < den.
*
* @param f fractional number
* @param val integer value
* @param num must be >= 0
* @param den must be >= 1
*/
static
void
frac_init
(
AVFrac
*
f
,
int64_t
val
,
int64_t
num
,
int64_t
den
)
{
num
+=
(
den
>>
1
);
if
(
num
>=
den
)
{
val
+=
num
/
den
;
num
=
num
%
den
;
}
f
->
val
=
val
;
f
->
num
=
num
;
f
->
den
=
den
;
}
/**
* Fractional addition to f: f = f + (incr / f->den).
*
* @param f fractional number
* @param incr increment, can be positive or negative
*/
static
void
frac_add
(
AVFrac
*
f
,
int64_t
incr
)
{
int64_t
num
,
den
;
num
=
f
->
num
+
incr
;
den
=
f
->
den
;
if
(
num
<
0
)
{
f
->
val
+=
num
/
den
;
num
=
num
%
den
;
if
(
num
<
0
)
{
num
+=
den
;
f
->
val
--
;
}
}
else
if
(
num
>=
den
)
{
f
->
val
+=
num
/
den
;
num
=
num
%
den
;
}
f
->
num
=
num
;
}
static
int
validate_codec_tag
(
AVFormatContext
*
s
,
AVStream
*
st
)
{
const
AVCodecTag
*
avctag
;
int
n
;
enum
AVCodecID
id
=
AV_CODEC_ID_NONE
;
unsigned
int
tag
=
0
;
/**
* Check that tag + id is in the table
* If neither is in the table -> OK
* If tag is in the table with another id -> FAIL
* If id is in the table with another tag -> FAIL unless strict < normal
*/
for
(
n
=
0
;
s
->
oformat
->
codec_tag
[
n
];
n
++
)
{
avctag
=
s
->
oformat
->
codec_tag
[
n
];
while
(
avctag
->
id
!=
AV_CODEC_ID_NONE
)
{
if
(
avpriv_toupper4
(
avctag
->
tag
)
==
avpriv_toupper4
(
st
->
codec
->
codec_tag
))
{
id
=
avctag
->
id
;
if
(
id
==
st
->
codec
->
codec_id
)
return
1
;
}
if
(
avctag
->
id
==
st
->
codec
->
codec_id
)
tag
=
avctag
->
tag
;
avctag
++
;
}
}
if
(
id
!=
AV_CODEC_ID_NONE
)
return
0
;
if
(
tag
&&
(
st
->
codec
->
strict_std_compliance
>=
FF_COMPLIANCE_NORMAL
))
return
0
;
return
1
;
}
int
avformat_write_header
(
AVFormatContext
*
s
,
AVDictionary
**
options
)
{
int
ret
=
0
,
i
;
AVStream
*
st
;
AVDictionary
*
tmp
=
NULL
;
if
(
options
)
av_dict_copy
(
&
tmp
,
*
options
,
0
);
if
((
ret
=
av_opt_set_dict
(
s
,
&
tmp
))
<
0
)
goto
fail
;
// some sanity checks
if
(
s
->
nb_streams
==
0
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NOSTREAMS
))
{
av_log
(
s
,
AV_LOG_ERROR
,
"no streams
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
st
=
s
->
streams
[
i
];
switch
(
st
->
codec
->
codec_type
)
{
case
AVMEDIA_TYPE_AUDIO
:
if
(
st
->
codec
->
sample_rate
<=
0
)
{
av_log
(
s
,
AV_LOG_ERROR
,
"sample rate not set
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
if
(
!
st
->
codec
->
block_align
)
st
->
codec
->
block_align
=
st
->
codec
->
channels
*
av_get_bits_per_sample
(
st
->
codec
->
codec_id
)
>>
3
;
break
;
case
AVMEDIA_TYPE_VIDEO
:
if
(
st
->
codec
->
time_base
.
num
<=
0
||
st
->
codec
->
time_base
.
den
<=
0
)
{
//FIXME audio too?
av_log
(
s
,
AV_LOG_ERROR
,
"time base not set
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
if
((
st
->
codec
->
width
<=
0
||
st
->
codec
->
height
<=
0
)
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NODIMENSIONS
))
{
av_log
(
s
,
AV_LOG_ERROR
,
"dimensions not set
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
if
(
av_cmp_q
(
st
->
sample_aspect_ratio
,
st
->
codec
->
sample_aspect_ratio
))
{
av_log
(
s
,
AV_LOG_ERROR
,
"Aspect ratio mismatch between muxer "
"(%d/%d) and encoder layer (%d/%d)
\n
"
,
st
->
sample_aspect_ratio
.
num
,
st
->
sample_aspect_ratio
.
den
,
st
->
codec
->
sample_aspect_ratio
.
num
,
st
->
codec
->
sample_aspect_ratio
.
den
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
break
;
}
if
(
s
->
oformat
->
codec_tag
)
{
if
(
st
->
codec
->
codec_tag
&&
st
->
codec
->
codec_id
==
AV_CODEC_ID_RAWVIDEO
&&
av_codec_get_tag
(
s
->
oformat
->
codec_tag
,
st
->
codec
->
codec_id
)
==
0
&&
!
validate_codec_tag
(
s
,
st
))
{
//the current rawvideo encoding system ends up setting the wrong codec_tag for avi, we override it here
st
->
codec
->
codec_tag
=
0
;
}
if
(
st
->
codec
->
codec_tag
)
{
if
(
!
validate_codec_tag
(
s
,
st
))
{
char
tagbuf
[
32
];
av_get_codec_tag_string
(
tagbuf
,
sizeof
(
tagbuf
),
st
->
codec
->
codec_tag
);
av_log
(
s
,
AV_LOG_ERROR
,
"Tag %s/0x%08x incompatible with output codec id '%d'
\n
"
,
tagbuf
,
st
->
codec
->
codec_tag
,
st
->
codec
->
codec_id
);
ret
=
AVERROR_INVALIDDATA
;
goto
fail
;
}
}
else
st
->
codec
->
codec_tag
=
av_codec_get_tag
(
s
->
oformat
->
codec_tag
,
st
->
codec
->
codec_id
);
}
if
(
s
->
oformat
->
flags
&
AVFMT_GLOBALHEADER
&&
!
(
st
->
codec
->
flags
&
CODEC_FLAG_GLOBAL_HEADER
))
av_log
(
s
,
AV_LOG_WARNING
,
"Codec for stream %d does not use global headers but container format requires global headers
\n
"
,
i
);
}
if
(
!
s
->
priv_data
&&
s
->
oformat
->
priv_data_size
>
0
)
{
s
->
priv_data
=
av_mallocz
(
s
->
oformat
->
priv_data_size
);
if
(
!
s
->
priv_data
)
{
ret
=
AVERROR
(
ENOMEM
);
goto
fail
;
}
if
(
s
->
oformat
->
priv_class
)
{
*
(
const
AVClass
**
)
s
->
priv_data
=
s
->
oformat
->
priv_class
;
av_opt_set_defaults
(
s
->
priv_data
);
if
((
ret
=
av_opt_set_dict
(
s
->
priv_data
,
&
tmp
))
<
0
)
goto
fail
;
}
}
/* set muxer identification string */
if
(
s
->
nb_streams
&&
!
(
s
->
streams
[
0
]
->
codec
->
flags
&
CODEC_FLAG_BITEXACT
))
{
av_dict_set
(
&
s
->
metadata
,
"encoder"
,
LIBAVFORMAT_IDENT
,
0
);
}
if
(
s
->
oformat
->
write_header
)
{
ret
=
s
->
oformat
->
write_header
(
s
);
if
(
ret
<
0
)
goto
fail
;
}
/* init PTS generation */
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
int64_t
den
=
AV_NOPTS_VALUE
;
st
=
s
->
streams
[
i
];
switch
(
st
->
codec
->
codec_type
)
{
case
AVMEDIA_TYPE_AUDIO
:
den
=
(
int64_t
)
st
->
time_base
.
num
*
st
->
codec
->
sample_rate
;
break
;
case
AVMEDIA_TYPE_VIDEO
:
den
=
(
int64_t
)
st
->
time_base
.
num
*
st
->
codec
->
time_base
.
den
;
break
;
default:
break
;
}
if
(
den
!=
AV_NOPTS_VALUE
)
{
if
(
den
<=
0
)
{
ret
=
AVERROR_INVALIDDATA
;
goto
fail
;
}
frac_init
(
&
st
->
pts
,
0
,
0
,
den
);
}
}
if
(
options
)
{
av_dict_free
(
options
);
*
options
=
tmp
;
}
return
0
;
fail:
av_dict_free
(
&
tmp
);
return
ret
;
}
//FIXME merge with compute_pkt_fields
static
int
compute_pkt_fields2
(
AVFormatContext
*
s
,
AVStream
*
st
,
AVPacket
*
pkt
)
{
int
delay
=
FFMAX
(
st
->
codec
->
has_b_frames
,
!!
st
->
codec
->
max_b_frames
);
int
num
,
den
,
frame_size
,
i
;
av_dlog
(
s
,
"compute_pkt_fields2: pts:%"
PRId64
" dts:%"
PRId64
" cur_dts:%"
PRId64
" b:%d size:%d st:%d
\n
"
,
pkt
->
pts
,
pkt
->
dts
,
st
->
cur_dts
,
delay
,
pkt
->
size
,
pkt
->
stream_index
);
/* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
* return AVERROR(EINVAL);*/
/* duration field */
if
(
pkt
->
duration
==
0
)
{
ff_compute_frame_duration
(
&
num
,
&
den
,
st
,
NULL
,
pkt
);
if
(
den
&&
num
)
{
pkt
->
duration
=
av_rescale
(
1
,
num
*
(
int64_t
)
st
->
time_base
.
den
*
st
->
codec
->
ticks_per_frame
,
den
*
(
int64_t
)
st
->
time_base
.
num
);
}
}
if
(
pkt
->
pts
==
AV_NOPTS_VALUE
&&
pkt
->
dts
!=
AV_NOPTS_VALUE
&&
delay
==
0
)
pkt
->
pts
=
pkt
->
dts
;
//XXX/FIXME this is a temporary hack until all encoders output pts
if
((
pkt
->
pts
==
0
||
pkt
->
pts
==
AV_NOPTS_VALUE
)
&&
pkt
->
dts
==
AV_NOPTS_VALUE
&&
!
delay
)
{
pkt
->
dts
=
// pkt->pts= st->cur_dts;
pkt
->
pts
=
st
->
pts
.
val
;
}
//calculate dts from pts
if
(
pkt
->
pts
!=
AV_NOPTS_VALUE
&&
pkt
->
dts
==
AV_NOPTS_VALUE
&&
delay
<=
MAX_REORDER_DELAY
)
{
st
->
pts_buffer
[
0
]
=
pkt
->
pts
;
for
(
i
=
1
;
i
<
delay
+
1
&&
st
->
pts_buffer
[
i
]
==
AV_NOPTS_VALUE
;
i
++
)
st
->
pts_buffer
[
i
]
=
pkt
->
pts
+
(
i
-
delay
-
1
)
*
pkt
->
duration
;
for
(
i
=
0
;
i
<
delay
&&
st
->
pts_buffer
[
i
]
>
st
->
pts_buffer
[
i
+
1
];
i
++
)
FFSWAP
(
int64_t
,
st
->
pts_buffer
[
i
],
st
->
pts_buffer
[
i
+
1
]);
pkt
->
dts
=
st
->
pts_buffer
[
0
];
}
if
(
st
->
cur_dts
&&
st
->
cur_dts
!=
AV_NOPTS_VALUE
&&
((
!
(
s
->
oformat
->
flags
&
AVFMT_TS_NONSTRICT
)
&&
st
->
cur_dts
>=
pkt
->
dts
)
||
st
->
cur_dts
>
pkt
->
dts
))
{
av_log
(
s
,
AV_LOG_ERROR
,
"Application provided invalid, non monotonically increasing dts to muxer in stream %d: %"
PRId64
" >= %"
PRId64
"
\n
"
,
st
->
index
,
st
->
cur_dts
,
pkt
->
dts
);
return
AVERROR
(
EINVAL
);
}
if
(
pkt
->
dts
!=
AV_NOPTS_VALUE
&&
pkt
->
pts
!=
AV_NOPTS_VALUE
&&
pkt
->
pts
<
pkt
->
dts
)
{
av_log
(
s
,
AV_LOG_ERROR
,
"pts < dts in stream %d
\n
"
,
st
->
index
);
return
AVERROR
(
EINVAL
);
}
av_dlog
(
s
,
"av_write_frame: pts2:%"
PRId64
" dts2:%"
PRId64
"
\n
"
,
pkt
->
pts
,
pkt
->
dts
);
st
->
cur_dts
=
pkt
->
dts
;
st
->
pts
.
val
=
pkt
->
dts
;
/* update pts */
switch
(
st
->
codec
->
codec_type
)
{
case
AVMEDIA_TYPE_AUDIO
:
frame_size
=
ff_get_audio_frame_size
(
st
->
codec
,
pkt
->
size
,
1
);
/* HACK/FIXME, we skip the initial 0 size packets as they are most
* likely equal to the encoder delay, but it would be better if we
* had the real timestamps from the encoder */
if
(
frame_size
>=
0
&&
(
pkt
->
size
||
st
->
pts
.
num
!=
st
->
pts
.
den
>>
1
||
st
->
pts
.
val
))
{
frac_add
(
&
st
->
pts
,
(
int64_t
)
st
->
time_base
.
den
*
frame_size
);
}
break
;
case
AVMEDIA_TYPE_VIDEO
:
frac_add
(
&
st
->
pts
,
(
int64_t
)
st
->
time_base
.
den
*
st
->
codec
->
time_base
.
num
);
break
;
default:
break
;
}
return
0
;
}
int
av_write_frame
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
int
ret
;
if
(
!
pkt
)
{
if
(
s
->
oformat
->
flags
&
AVFMT_ALLOW_FLUSH
)
return
s
->
oformat
->
write_packet
(
s
,
pkt
);
return
1
;
}
ret
=
compute_pkt_fields2
(
s
,
s
->
streams
[
pkt
->
stream_index
],
pkt
);
if
(
ret
<
0
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NOTIMESTAMPS
))
return
ret
;
ret
=
s
->
oformat
->
write_packet
(
s
,
pkt
);
if
(
ret
>=
0
)
s
->
streams
[
pkt
->
stream_index
]
->
nb_frames
++
;
return
ret
;
}
void
ff_interleave_add_packet
(
AVFormatContext
*
s
,
AVPacket
*
pkt
,
int
(
*
compare
)(
AVFormatContext
*
,
AVPacket
*
,
AVPacket
*
))
{
AVPacketList
**
next_point
,
*
this_pktl
;
this_pktl
=
av_mallocz
(
sizeof
(
AVPacketList
));
this_pktl
->
pkt
=
*
pkt
;
pkt
->
destruct
=
NULL
;
// do not free original but only the copy
av_dup_packet
(
&
this_pktl
->
pkt
);
// duplicate the packet if it uses non-alloced memory
if
(
s
->
streams
[
pkt
->
stream_index
]
->
last_in_packet_buffer
)
{
next_point
=
&
(
s
->
streams
[
pkt
->
stream_index
]
->
last_in_packet_buffer
->
next
);
}
else
next_point
=
&
s
->
packet_buffer
;
if
(
*
next_point
)
{
if
(
compare
(
s
,
&
s
->
packet_buffer_end
->
pkt
,
pkt
))
{
while
(
!
compare
(
s
,
&
(
*
next_point
)
->
pkt
,
pkt
))
next_point
=
&
(
*
next_point
)
->
next
;
goto
next_non_null
;
}
else
{
next_point
=
&
(
s
->
packet_buffer_end
->
next
);
}
}
assert
(
!*
next_point
);
s
->
packet_buffer_end
=
this_pktl
;
next_non_null:
this_pktl
->
next
=
*
next_point
;
s
->
streams
[
pkt
->
stream_index
]
->
last_in_packet_buffer
=
*
next_point
=
this_pktl
;
}
static
int
ff_interleave_compare_dts
(
AVFormatContext
*
s
,
AVPacket
*
next
,
AVPacket
*
pkt
)
{
AVStream
*
st
=
s
->
streams
[
pkt
->
stream_index
];
AVStream
*
st2
=
s
->
streams
[
next
->
stream_index
];
int
comp
=
av_compare_ts
(
next
->
dts
,
st2
->
time_base
,
pkt
->
dts
,
st
->
time_base
);
if
(
comp
==
0
)
return
pkt
->
stream_index
<
next
->
stream_index
;
return
comp
>
0
;
}
int
ff_interleave_packet_per_dts
(
AVFormatContext
*
s
,
AVPacket
*
out
,
AVPacket
*
pkt
,
int
flush
)
{
AVPacketList
*
pktl
;
int
stream_count
=
0
;
int
i
;
if
(
pkt
)
{
ff_interleave_add_packet
(
s
,
pkt
,
ff_interleave_compare_dts
);
}
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
stream_count
+=
!!
s
->
streams
[
i
]
->
last_in_packet_buffer
;
if
(
stream_count
&&
(
s
->
nb_streams
==
stream_count
||
flush
))
{
pktl
=
s
->
packet_buffer
;
*
out
=
pktl
->
pkt
;
s
->
packet_buffer
=
pktl
->
next
;
if
(
!
s
->
packet_buffer
)
s
->
packet_buffer_end
=
NULL
;
if
(
s
->
streams
[
out
->
stream_index
]
->
last_in_packet_buffer
==
pktl
)
s
->
streams
[
out
->
stream_index
]
->
last_in_packet_buffer
=
NULL
;
av_freep
(
&
pktl
);
return
1
;
}
else
{
av_init_packet
(
out
);
return
0
;
}
}
#if FF_API_INTERLEAVE_PACKET
int
av_interleave_packet_per_dts
(
AVFormatContext
*
s
,
AVPacket
*
out
,
AVPacket
*
pkt
,
int
flush
)
{
return
ff_interleave_packet_per_dts
(
s
,
out
,
pkt
,
flush
);
}
#endif
/**
* Interleave an AVPacket correctly so it can be muxed.
* @param out the interleaved packet will be output here
* @param in the input packet
* @param flush 1 if no further packets are available as input and all
* remaining packets should be output
* @return 1 if a packet was output, 0 if no packet could be output,
* < 0 if an error occurred
*/
static
int
interleave_packet
(
AVFormatContext
*
s
,
AVPacket
*
out
,
AVPacket
*
in
,
int
flush
)
{
if
(
s
->
oformat
->
interleave_packet
)
{
int
ret
=
s
->
oformat
->
interleave_packet
(
s
,
out
,
in
,
flush
);
if
(
in
)
av_free_packet
(
in
);
return
ret
;
}
else
return
ff_interleave_packet_per_dts
(
s
,
out
,
in
,
flush
);
}
int
av_interleaved_write_frame
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
int
ret
,
flush
=
0
;
if
(
pkt
)
{
AVStream
*
st
=
s
->
streams
[
pkt
->
stream_index
];
//FIXME/XXX/HACK drop zero sized packets
if
(
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_AUDIO
&&
pkt
->
size
==
0
)
return
0
;
av_dlog
(
s
,
"av_interleaved_write_frame size:%d dts:%"
PRId64
" pts:%"
PRId64
"
\n
"
,
pkt
->
size
,
pkt
->
dts
,
pkt
->
pts
);
if
((
ret
=
compute_pkt_fields2
(
s
,
st
,
pkt
))
<
0
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NOTIMESTAMPS
))
return
ret
;
if
(
pkt
->
dts
==
AV_NOPTS_VALUE
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NOTIMESTAMPS
))
return
AVERROR
(
EINVAL
);
}
else
{
av_dlog
(
s
,
"av_interleaved_write_frame FLUSH
\n
"
);
flush
=
1
;
}
for
(;;
)
{
AVPacket
opkt
;
int
ret
=
interleave_packet
(
s
,
&
opkt
,
pkt
,
flush
);
if
(
ret
<=
0
)
//FIXME cleanup needed for ret<0 ?
return
ret
;
ret
=
s
->
oformat
->
write_packet
(
s
,
&
opkt
);
if
(
ret
>=
0
)
s
->
streams
[
opkt
.
stream_index
]
->
nb_frames
++
;
av_free_packet
(
&
opkt
);
pkt
=
NULL
;
if
(
ret
<
0
)
return
ret
;
}
}
int
av_write_trailer
(
AVFormatContext
*
s
)
{
int
ret
,
i
;
for
(;;
)
{
AVPacket
pkt
;
ret
=
interleave_packet
(
s
,
&
pkt
,
NULL
,
1
);
if
(
ret
<
0
)
//FIXME cleanup needed for ret<0 ?
goto
fail
;
if
(
!
ret
)
break
;
ret
=
s
->
oformat
->
write_packet
(
s
,
&
pkt
);
if
(
ret
>=
0
)
s
->
streams
[
pkt
.
stream_index
]
->
nb_frames
++
;
av_free_packet
(
&
pkt
);
if
(
ret
<
0
)
goto
fail
;
}
if
(
s
->
oformat
->
write_trailer
)
ret
=
s
->
oformat
->
write_trailer
(
s
);
if
(
!
(
s
->
oformat
->
flags
&
AVFMT_NOFILE
))
avio_flush
(
s
->
pb
);
fail:
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
av_freep
(
&
s
->
streams
[
i
]
->
priv_data
);
av_freep
(
&
s
->
streams
[
i
]
->
index_entries
);
}
if
(
s
->
oformat
->
priv_class
)
av_opt_free
(
s
->
priv_data
);
av_freep
(
&
s
->
priv_data
);
return
ret
;
}
libavformat/utils.c
View file @
55f9037f
...
@@ -68,56 +68,6 @@ const char *avformat_license(void)
...
@@ -68,56 +68,6 @@ const char *avformat_license(void)
return
LICENSE_PREFIX
LIBAV_LICENSE
+
sizeof
(
LICENSE_PREFIX
)
-
1
;
return
LICENSE_PREFIX
LIBAV_LICENSE
+
sizeof
(
LICENSE_PREFIX
)
-
1
;
}
}
/* fraction handling */
/**
* f = val + (num / den) + 0.5.
*
* 'num' is normalized so that it is such as 0 <= num < den.
*
* @param f fractional number
* @param val integer value
* @param num must be >= 0
* @param den must be >= 1
*/
static
void
frac_init
(
AVFrac
*
f
,
int64_t
val
,
int64_t
num
,
int64_t
den
)
{
num
+=
(
den
>>
1
);
if
(
num
>=
den
)
{
val
+=
num
/
den
;
num
=
num
%
den
;
}
f
->
val
=
val
;
f
->
num
=
num
;
f
->
den
=
den
;
}
/**
* Fractional addition to f: f = f + (incr / f->den).
*
* @param f fractional number
* @param incr increment, can be positive or negative
*/
static
void
frac_add
(
AVFrac
*
f
,
int64_t
incr
)
{
int64_t
num
,
den
;
num
=
f
->
num
+
incr
;
den
=
f
->
den
;
if
(
num
<
0
)
{
f
->
val
+=
num
/
den
;
num
=
num
%
den
;
if
(
num
<
0
)
{
num
+=
den
;
f
->
val
--
;
}
}
else
if
(
num
>=
den
)
{
f
->
val
+=
num
/
den
;
num
=
num
%
den
;
}
f
->
num
=
num
;
}
/** head of registered input format linked list */
/** head of registered input format linked list */
static
AVInputFormat
*
first_iformat
=
NULL
;
static
AVInputFormat
*
first_iformat
=
NULL
;
/** head of registered output format linked list */
/** head of registered output format linked list */
...
@@ -734,7 +684,7 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -734,7 +684,7 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt)
/**
/**
* Get the number of samples of an audio frame. Return -1 on error.
* Get the number of samples of an audio frame. Return -1 on error.
*/
*/
static
int
get_audio_frame_size
(
AVCodecContext
*
enc
,
int
size
,
int
mux
)
int
ff_
get_audio_frame_size
(
AVCodecContext
*
enc
,
int
size
,
int
mux
)
{
{
int
frame_size
;
int
frame_size
;
...
@@ -756,8 +706,8 @@ static int get_audio_frame_size(AVCodecContext *enc, int size, int mux)
...
@@ -756,8 +706,8 @@ static int get_audio_frame_size(AVCodecContext *enc, int size, int mux)
/**
/**
* Return the frame duration in seconds. Return 0 if not available.
* Return the frame duration in seconds. Return 0 if not available.
*/
*/
static
void
compute_frame_duration
(
int
*
pnum
,
int
*
pden
,
AVStream
*
st
,
void
ff_
compute_frame_duration
(
int
*
pnum
,
int
*
pden
,
AVStream
*
st
,
AVCodecParserContext
*
pc
,
AVPacket
*
pkt
)
AVCodecParserContext
*
pc
,
AVPacket
*
pkt
)
{
{
int
frame_size
;
int
frame_size
;
...
@@ -785,7 +735,7 @@ static void compute_frame_duration(int *pnum, int *pden, AVStream *st,
...
@@ -785,7 +735,7 @@ static void compute_frame_duration(int *pnum, int *pden, AVStream *st,
}
}
break
;
break
;
case
AVMEDIA_TYPE_AUDIO
:
case
AVMEDIA_TYPE_AUDIO
:
frame_size
=
get_audio_frame_size
(
st
->
codec
,
pkt
->
size
,
0
);
frame_size
=
ff_
get_audio_frame_size
(
st
->
codec
,
pkt
->
size
,
0
);
if
(
frame_size
<=
0
||
st
->
codec
->
sample_rate
<=
0
)
if
(
frame_size
<=
0
||
st
->
codec
->
sample_rate
<=
0
)
break
;
break
;
*
pnum
=
frame_size
;
*
pnum
=
frame_size
;
...
@@ -909,7 +859,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
...
@@ -909,7 +859,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
}
}
if
(
pkt
->
duration
==
0
&&
st
->
codec
->
codec_type
!=
AVMEDIA_TYPE_AUDIO
)
{
if
(
pkt
->
duration
==
0
&&
st
->
codec
->
codec_type
!=
AVMEDIA_TYPE_AUDIO
)
{
compute_frame_duration
(
&
num
,
&
den
,
st
,
pc
,
pkt
);
ff_
compute_frame_duration
(
&
num
,
&
den
,
st
,
pc
,
pkt
);
if
(
den
&&
num
)
{
if
(
den
&&
num
)
{
pkt
->
duration
=
av_rescale_rnd
(
1
,
num
*
(
int64_t
)
st
->
time_base
.
den
,
den
*
(
int64_t
)
st
->
time_base
.
num
,
AV_ROUND_DOWN
);
pkt
->
duration
=
av_rescale_rnd
(
1
,
num
*
(
int64_t
)
st
->
time_base
.
den
,
den
*
(
int64_t
)
st
->
time_base
.
num
,
AV_ROUND_DOWN
);
...
@@ -984,7 +934,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
...
@@ -984,7 +934,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_AUDIO
)
{
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_AUDIO
)
{
int
duration
=
pkt
->
duration
;
int
duration
=
pkt
->
duration
;
if
(
!
duration
&&
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_AUDIO
)
{
if
(
!
duration
&&
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_AUDIO
)
{
compute_frame_duration
(
&
num
,
&
den
,
st
,
pc
,
pkt
);
ff_
compute_frame_duration
(
&
num
,
&
den
,
st
,
pc
,
pkt
);
if
(
den
&&
num
)
{
if
(
den
&&
num
)
{
duration
=
av_rescale_rnd
(
1
,
num
*
(
int64_t
)
st
->
time_base
.
den
,
duration
=
av_rescale_rnd
(
1
,
num
*
(
int64_t
)
st
->
time_base
.
den
,
den
*
(
int64_t
)
st
->
time_base
.
num
,
den
*
(
int64_t
)
st
->
time_base
.
num
,
...
@@ -2846,467 +2796,6 @@ AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base,
...
@@ -2846,467 +2796,6 @@ AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base,
return
chapter
;
return
chapter
;
}
}
/************************************************************/
/* output media file */
static
int
validate_codec_tag
(
AVFormatContext
*
s
,
AVStream
*
st
)
{
const
AVCodecTag
*
avctag
;
int
n
;
enum
AVCodecID
id
=
AV_CODEC_ID_NONE
;
unsigned
int
tag
=
0
;
/**
* Check that tag + id is in the table
* If neither is in the table -> OK
* If tag is in the table with another id -> FAIL
* If id is in the table with another tag -> FAIL unless strict < normal
*/
for
(
n
=
0
;
s
->
oformat
->
codec_tag
[
n
];
n
++
)
{
avctag
=
s
->
oformat
->
codec_tag
[
n
];
while
(
avctag
->
id
!=
AV_CODEC_ID_NONE
)
{
if
(
avpriv_toupper4
(
avctag
->
tag
)
==
avpriv_toupper4
(
st
->
codec
->
codec_tag
))
{
id
=
avctag
->
id
;
if
(
id
==
st
->
codec
->
codec_id
)
return
1
;
}
if
(
avctag
->
id
==
st
->
codec
->
codec_id
)
tag
=
avctag
->
tag
;
avctag
++
;
}
}
if
(
id
!=
AV_CODEC_ID_NONE
)
return
0
;
if
(
tag
&&
(
st
->
codec
->
strict_std_compliance
>=
FF_COMPLIANCE_NORMAL
))
return
0
;
return
1
;
}
int
avformat_write_header
(
AVFormatContext
*
s
,
AVDictionary
**
options
)
{
int
ret
=
0
,
i
;
AVStream
*
st
;
AVDictionary
*
tmp
=
NULL
;
if
(
options
)
av_dict_copy
(
&
tmp
,
*
options
,
0
);
if
((
ret
=
av_opt_set_dict
(
s
,
&
tmp
))
<
0
)
goto
fail
;
// some sanity checks
if
(
s
->
nb_streams
==
0
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NOSTREAMS
))
{
av_log
(
s
,
AV_LOG_ERROR
,
"no streams
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
st
=
s
->
streams
[
i
];
switch
(
st
->
codec
->
codec_type
)
{
case
AVMEDIA_TYPE_AUDIO
:
if
(
st
->
codec
->
sample_rate
<=
0
){
av_log
(
s
,
AV_LOG_ERROR
,
"sample rate not set
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
if
(
!
st
->
codec
->
block_align
)
st
->
codec
->
block_align
=
st
->
codec
->
channels
*
av_get_bits_per_sample
(
st
->
codec
->
codec_id
)
>>
3
;
break
;
case
AVMEDIA_TYPE_VIDEO
:
if
(
st
->
codec
->
time_base
.
num
<=
0
||
st
->
codec
->
time_base
.
den
<=
0
){
//FIXME audio too?
av_log
(
s
,
AV_LOG_ERROR
,
"time base not set
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
if
((
st
->
codec
->
width
<=
0
||
st
->
codec
->
height
<=
0
)
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NODIMENSIONS
)){
av_log
(
s
,
AV_LOG_ERROR
,
"dimensions not set
\n
"
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
if
(
av_cmp_q
(
st
->
sample_aspect_ratio
,
st
->
codec
->
sample_aspect_ratio
)){
av_log
(
s
,
AV_LOG_ERROR
,
"Aspect ratio mismatch between muxer "
"(%d/%d) and encoder layer (%d/%d)
\n
"
,
st
->
sample_aspect_ratio
.
num
,
st
->
sample_aspect_ratio
.
den
,
st
->
codec
->
sample_aspect_ratio
.
num
,
st
->
codec
->
sample_aspect_ratio
.
den
);
ret
=
AVERROR
(
EINVAL
);
goto
fail
;
}
break
;
}
if
(
s
->
oformat
->
codec_tag
){
if
(
st
->
codec
->
codec_tag
&&
st
->
codec
->
codec_id
==
AV_CODEC_ID_RAWVIDEO
&&
av_codec_get_tag
(
s
->
oformat
->
codec_tag
,
st
->
codec
->
codec_id
)
==
0
&&
!
validate_codec_tag
(
s
,
st
)){
//the current rawvideo encoding system ends up setting the wrong codec_tag for avi, we override it here
st
->
codec
->
codec_tag
=
0
;
}
if
(
st
->
codec
->
codec_tag
){
if
(
!
validate_codec_tag
(
s
,
st
))
{
char
tagbuf
[
32
];
av_get_codec_tag_string
(
tagbuf
,
sizeof
(
tagbuf
),
st
->
codec
->
codec_tag
);
av_log
(
s
,
AV_LOG_ERROR
,
"Tag %s/0x%08x incompatible with output codec id '%d'
\n
"
,
tagbuf
,
st
->
codec
->
codec_tag
,
st
->
codec
->
codec_id
);
ret
=
AVERROR_INVALIDDATA
;
goto
fail
;
}
}
else
st
->
codec
->
codec_tag
=
av_codec_get_tag
(
s
->
oformat
->
codec_tag
,
st
->
codec
->
codec_id
);
}
if
(
s
->
oformat
->
flags
&
AVFMT_GLOBALHEADER
&&
!
(
st
->
codec
->
flags
&
CODEC_FLAG_GLOBAL_HEADER
))
av_log
(
s
,
AV_LOG_WARNING
,
"Codec for stream %d does not use global headers but container format requires global headers
\n
"
,
i
);
}
if
(
!
s
->
priv_data
&&
s
->
oformat
->
priv_data_size
>
0
)
{
s
->
priv_data
=
av_mallocz
(
s
->
oformat
->
priv_data_size
);
if
(
!
s
->
priv_data
)
{
ret
=
AVERROR
(
ENOMEM
);
goto
fail
;
}
if
(
s
->
oformat
->
priv_class
)
{
*
(
const
AVClass
**
)
s
->
priv_data
=
s
->
oformat
->
priv_class
;
av_opt_set_defaults
(
s
->
priv_data
);
if
((
ret
=
av_opt_set_dict
(
s
->
priv_data
,
&
tmp
))
<
0
)
goto
fail
;
}
}
/* set muxer identification string */
if
(
s
->
nb_streams
&&
!
(
s
->
streams
[
0
]
->
codec
->
flags
&
CODEC_FLAG_BITEXACT
))
{
av_dict_set
(
&
s
->
metadata
,
"encoder"
,
LIBAVFORMAT_IDENT
,
0
);
}
if
(
s
->
oformat
->
write_header
){
ret
=
s
->
oformat
->
write_header
(
s
);
if
(
ret
<
0
)
goto
fail
;
}
/* init PTS generation */
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
int64_t
den
=
AV_NOPTS_VALUE
;
st
=
s
->
streams
[
i
];
switch
(
st
->
codec
->
codec_type
)
{
case
AVMEDIA_TYPE_AUDIO
:
den
=
(
int64_t
)
st
->
time_base
.
num
*
st
->
codec
->
sample_rate
;
break
;
case
AVMEDIA_TYPE_VIDEO
:
den
=
(
int64_t
)
st
->
time_base
.
num
*
st
->
codec
->
time_base
.
den
;
break
;
default
:
break
;
}
if
(
den
!=
AV_NOPTS_VALUE
)
{
if
(
den
<=
0
)
{
ret
=
AVERROR_INVALIDDATA
;
goto
fail
;
}
frac_init
(
&
st
->
pts
,
0
,
0
,
den
);
}
}
if
(
options
)
{
av_dict_free
(
options
);
*
options
=
tmp
;
}
return
0
;
fail
:
av_dict_free
(
&
tmp
);
return
ret
;
}
//FIXME merge with compute_pkt_fields
static
int
compute_pkt_fields2
(
AVFormatContext
*
s
,
AVStream
*
st
,
AVPacket
*
pkt
){
int
delay
=
FFMAX
(
st
->
codec
->
has_b_frames
,
!!
st
->
codec
->
max_b_frames
);
int
num
,
den
,
frame_size
,
i
;
av_dlog
(
s
,
"compute_pkt_fields2: pts:%"
PRId64
" dts:%"
PRId64
" cur_dts:%"
PRId64
" b:%d size:%d st:%d
\n
"
,
pkt
->
pts
,
pkt
->
dts
,
st
->
cur_dts
,
delay
,
pkt
->
size
,
pkt
->
stream_index
);
/* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
return AVERROR(EINVAL);*/
/* duration field */
if
(
pkt
->
duration
==
0
)
{
compute_frame_duration
(
&
num
,
&
den
,
st
,
NULL
,
pkt
);
if
(
den
&&
num
)
{
pkt
->
duration
=
av_rescale
(
1
,
num
*
(
int64_t
)
st
->
time_base
.
den
*
st
->
codec
->
ticks_per_frame
,
den
*
(
int64_t
)
st
->
time_base
.
num
);
}
}
if
(
pkt
->
pts
==
AV_NOPTS_VALUE
&&
pkt
->
dts
!=
AV_NOPTS_VALUE
&&
delay
==
0
)
pkt
->
pts
=
pkt
->
dts
;
//XXX/FIXME this is a temporary hack until all encoders output pts
if
((
pkt
->
pts
==
0
||
pkt
->
pts
==
AV_NOPTS_VALUE
)
&&
pkt
->
dts
==
AV_NOPTS_VALUE
&&
!
delay
){
pkt
->
dts
=
// pkt->pts= st->cur_dts;
pkt
->
pts
=
st
->
pts
.
val
;
}
//calculate dts from pts
if
(
pkt
->
pts
!=
AV_NOPTS_VALUE
&&
pkt
->
dts
==
AV_NOPTS_VALUE
&&
delay
<=
MAX_REORDER_DELAY
){
st
->
pts_buffer
[
0
]
=
pkt
->
pts
;
for
(
i
=
1
;
i
<
delay
+
1
&&
st
->
pts_buffer
[
i
]
==
AV_NOPTS_VALUE
;
i
++
)
st
->
pts_buffer
[
i
]
=
pkt
->
pts
+
(
i
-
delay
-
1
)
*
pkt
->
duration
;
for
(
i
=
0
;
i
<
delay
&&
st
->
pts_buffer
[
i
]
>
st
->
pts_buffer
[
i
+
1
];
i
++
)
FFSWAP
(
int64_t
,
st
->
pts_buffer
[
i
],
st
->
pts_buffer
[
i
+
1
]);
pkt
->
dts
=
st
->
pts_buffer
[
0
];
}
if
(
st
->
cur_dts
&&
st
->
cur_dts
!=
AV_NOPTS_VALUE
&&
((
!
(
s
->
oformat
->
flags
&
AVFMT_TS_NONSTRICT
)
&&
st
->
cur_dts
>=
pkt
->
dts
)
||
st
->
cur_dts
>
pkt
->
dts
))
{
av_log
(
s
,
AV_LOG_ERROR
,
"Application provided invalid, non monotonically increasing dts to muxer in stream %d: %"
PRId64
" >= %"
PRId64
"
\n
"
,
st
->
index
,
st
->
cur_dts
,
pkt
->
dts
);
return
AVERROR
(
EINVAL
);
}
if
(
pkt
->
dts
!=
AV_NOPTS_VALUE
&&
pkt
->
pts
!=
AV_NOPTS_VALUE
&&
pkt
->
pts
<
pkt
->
dts
){
av_log
(
s
,
AV_LOG_ERROR
,
"pts < dts in stream %d
\n
"
,
st
->
index
);
return
AVERROR
(
EINVAL
);
}
av_dlog
(
s
,
"av_write_frame: pts2:%"
PRId64
" dts2:%"
PRId64
"
\n
"
,
pkt
->
pts
,
pkt
->
dts
);
st
->
cur_dts
=
pkt
->
dts
;
st
->
pts
.
val
=
pkt
->
dts
;
/* update pts */
switch
(
st
->
codec
->
codec_type
)
{
case
AVMEDIA_TYPE_AUDIO
:
frame_size
=
get_audio_frame_size
(
st
->
codec
,
pkt
->
size
,
1
);
/* HACK/FIXME, we skip the initial 0 size packets as they are most
likely equal to the encoder delay, but it would be better if we
had the real timestamps from the encoder */
if
(
frame_size
>=
0
&&
(
pkt
->
size
||
st
->
pts
.
num
!=
st
->
pts
.
den
>>
1
||
st
->
pts
.
val
))
{
frac_add
(
&
st
->
pts
,
(
int64_t
)
st
->
time_base
.
den
*
frame_size
);
}
break
;
case
AVMEDIA_TYPE_VIDEO
:
frac_add
(
&
st
->
pts
,
(
int64_t
)
st
->
time_base
.
den
*
st
->
codec
->
time_base
.
num
);
break
;
default
:
break
;
}
return
0
;
}
int
av_write_frame
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
int
ret
;
if
(
!
pkt
)
{
if
(
s
->
oformat
->
flags
&
AVFMT_ALLOW_FLUSH
)
return
s
->
oformat
->
write_packet
(
s
,
pkt
);
return
1
;
}
ret
=
compute_pkt_fields2
(
s
,
s
->
streams
[
pkt
->
stream_index
],
pkt
);
if
(
ret
<
0
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NOTIMESTAMPS
))
return
ret
;
ret
=
s
->
oformat
->
write_packet
(
s
,
pkt
);
if
(
ret
>=
0
)
s
->
streams
[
pkt
->
stream_index
]
->
nb_frames
++
;
return
ret
;
}
void
ff_interleave_add_packet
(
AVFormatContext
*
s
,
AVPacket
*
pkt
,
int
(
*
compare
)(
AVFormatContext
*
,
AVPacket
*
,
AVPacket
*
))
{
AVPacketList
**
next_point
,
*
this_pktl
;
this_pktl
=
av_mallocz
(
sizeof
(
AVPacketList
));
this_pktl
->
pkt
=
*
pkt
;
pkt
->
destruct
=
NULL
;
// do not free original but only the copy
av_dup_packet
(
&
this_pktl
->
pkt
);
// duplicate the packet if it uses non-alloced memory
if
(
s
->
streams
[
pkt
->
stream_index
]
->
last_in_packet_buffer
){
next_point
=
&
(
s
->
streams
[
pkt
->
stream_index
]
->
last_in_packet_buffer
->
next
);
}
else
next_point
=
&
s
->
packet_buffer
;
if
(
*
next_point
){
if
(
compare
(
s
,
&
s
->
packet_buffer_end
->
pkt
,
pkt
)){
while
(
!
compare
(
s
,
&
(
*
next_point
)
->
pkt
,
pkt
)){
next_point
=
&
(
*
next_point
)
->
next
;
}
goto
next_non_null
;
}
else
{
next_point
=
&
(
s
->
packet_buffer_end
->
next
);
}
}
assert
(
!*
next_point
);
s
->
packet_buffer_end
=
this_pktl
;
next_non_null
:
this_pktl
->
next
=
*
next_point
;
s
->
streams
[
pkt
->
stream_index
]
->
last_in_packet_buffer
=
*
next_point
=
this_pktl
;
}
static
int
ff_interleave_compare_dts
(
AVFormatContext
*
s
,
AVPacket
*
next
,
AVPacket
*
pkt
)
{
AVStream
*
st
=
s
->
streams
[
pkt
->
stream_index
];
AVStream
*
st2
=
s
->
streams
[
next
->
stream_index
];
int
comp
=
av_compare_ts
(
next
->
dts
,
st2
->
time_base
,
pkt
->
dts
,
st
->
time_base
);
if
(
comp
==
0
)
return
pkt
->
stream_index
<
next
->
stream_index
;
return
comp
>
0
;
}
int
ff_interleave_packet_per_dts
(
AVFormatContext
*
s
,
AVPacket
*
out
,
AVPacket
*
pkt
,
int
flush
)
{
AVPacketList
*
pktl
;
int
stream_count
=
0
;
int
i
;
if
(
pkt
){
ff_interleave_add_packet
(
s
,
pkt
,
ff_interleave_compare_dts
);
}
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
stream_count
+=
!!
s
->
streams
[
i
]
->
last_in_packet_buffer
;
if
(
stream_count
&&
(
s
->
nb_streams
==
stream_count
||
flush
)){
pktl
=
s
->
packet_buffer
;
*
out
=
pktl
->
pkt
;
s
->
packet_buffer
=
pktl
->
next
;
if
(
!
s
->
packet_buffer
)
s
->
packet_buffer_end
=
NULL
;
if
(
s
->
streams
[
out
->
stream_index
]
->
last_in_packet_buffer
==
pktl
)
s
->
streams
[
out
->
stream_index
]
->
last_in_packet_buffer
=
NULL
;
av_freep
(
&
pktl
);
return
1
;
}
else
{
av_init_packet
(
out
);
return
0
;
}
}
#if FF_API_INTERLEAVE_PACKET
int
av_interleave_packet_per_dts
(
AVFormatContext
*
s
,
AVPacket
*
out
,
AVPacket
*
pkt
,
int
flush
)
{
return
ff_interleave_packet_per_dts
(
s
,
out
,
pkt
,
flush
);
}
#endif
/**
* Interleave an AVPacket correctly so it can be muxed.
* @param out the interleaved packet will be output here
* @param in the input packet
* @param flush 1 if no further packets are available as input and all
* remaining packets should be output
* @return 1 if a packet was output, 0 if no packet could be output,
* < 0 if an error occurred
*/
static
int
interleave_packet
(
AVFormatContext
*
s
,
AVPacket
*
out
,
AVPacket
*
in
,
int
flush
){
if
(
s
->
oformat
->
interleave_packet
)
{
int
ret
=
s
->
oformat
->
interleave_packet
(
s
,
out
,
in
,
flush
);
if
(
in
)
av_free_packet
(
in
);
return
ret
;
}
else
return
ff_interleave_packet_per_dts
(
s
,
out
,
in
,
flush
);
}
int
av_interleaved_write_frame
(
AVFormatContext
*
s
,
AVPacket
*
pkt
){
int
ret
,
flush
=
0
;
if
(
pkt
)
{
AVStream
*
st
=
s
->
streams
[
pkt
->
stream_index
];
//FIXME/XXX/HACK drop zero sized packets
if
(
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_AUDIO
&&
pkt
->
size
==
0
)
return
0
;
av_dlog
(
s
,
"av_interleaved_write_frame size:%d dts:%"
PRId64
" pts:%"
PRId64
"
\n
"
,
pkt
->
size
,
pkt
->
dts
,
pkt
->
pts
);
if
((
ret
=
compute_pkt_fields2
(
s
,
st
,
pkt
))
<
0
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NOTIMESTAMPS
))
return
ret
;
if
(
pkt
->
dts
==
AV_NOPTS_VALUE
&&
!
(
s
->
oformat
->
flags
&
AVFMT_NOTIMESTAMPS
))
return
AVERROR
(
EINVAL
);
}
else
{
av_dlog
(
s
,
"av_interleaved_write_frame FLUSH
\n
"
);
flush
=
1
;
}
for
(;;){
AVPacket
opkt
;
int
ret
=
interleave_packet
(
s
,
&
opkt
,
pkt
,
flush
);
if
(
ret
<=
0
)
//FIXME cleanup needed for ret<0 ?
return
ret
;
ret
=
s
->
oformat
->
write_packet
(
s
,
&
opkt
);
if
(
ret
>=
0
)
s
->
streams
[
opkt
.
stream_index
]
->
nb_frames
++
;
av_free_packet
(
&
opkt
);
pkt
=
NULL
;
if
(
ret
<
0
)
return
ret
;
}
}
int
av_write_trailer
(
AVFormatContext
*
s
)
{
int
ret
,
i
;
for
(;;)
{
AVPacket
pkt
;
ret
=
interleave_packet
(
s
,
&
pkt
,
NULL
,
1
);
if
(
ret
<
0
)
//FIXME cleanup needed for ret<0 ?
goto
fail
;
if
(
!
ret
)
break
;
ret
=
s
->
oformat
->
write_packet
(
s
,
&
pkt
);
if
(
ret
>=
0
)
s
->
streams
[
pkt
.
stream_index
]
->
nb_frames
++
;
av_free_packet
(
&
pkt
);
if
(
ret
<
0
)
goto
fail
;
}
if
(
s
->
oformat
->
write_trailer
)
ret
=
s
->
oformat
->
write_trailer
(
s
);
if
(
!
(
s
->
oformat
->
flags
&
AVFMT_NOFILE
))
avio_flush
(
s
->
pb
);
fail
:
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
av_freep
(
&
s
->
streams
[
i
]
->
priv_data
);
av_freep
(
&
s
->
streams
[
i
]
->
index_entries
);
}
if
(
s
->
oformat
->
priv_class
)
av_opt_free
(
s
->
priv_data
);
av_freep
(
&
s
->
priv_data
);
return
ret
;
}
void
ff_program_add_stream_index
(
AVFormatContext
*
ac
,
int
progid
,
unsigned
int
idx
)
void
ff_program_add_stream_index
(
AVFormatContext
*
ac
,
int
progid
,
unsigned
int
idx
)
{
{
int
i
,
j
;
int
i
,
j
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment