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
9fb2e234
Commit
9fb2e234
authored
Mar 05, 2012
by
Clément Bœsch
Committed by
Clément Bœsch
Jun 11, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
movenc: add timecode track support.
parent
9846a9c7
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
148 additions
and
12 deletions
+148
-12
general.texi
doc/general.texi
+1
-1
movenc.c
libavformat/movenc.c
+138
-6
movenc.h
libavformat/movenc.h
+5
-1
mov
tests/ref/lavf/mov
+4
-4
No files found.
doc/general.texi
View file @
9fb2e234
...
@@ -893,7 +893,7 @@ performance on systems without hardware floating point support).
...
@@ -893,7 +893,7 @@ performance on systems without hardware floating point support).
@item AVI @tab X @tab X
@item AVI @tab X @tab X
@item DV @tab X @tab X
@item DV @tab X @tab X
@item GXF @tab X @tab X
@item GXF @tab X @tab X
@item MOV @tab X @tab
@item MOV @tab X @tab
X
@item MPEG1/2 @tab X @tab X
@item MPEG1/2 @tab X @tab X
@item MXF @tab X @tab X
@item MXF @tab X @tab X
@end multitable
@end multitable
...
...
libavformat/movenc.c
View file @
9fb2e234
...
@@ -1095,6 +1095,26 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
...
@@ -1095,6 +1095,26 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
return
update_size
(
pb
,
pos
);
return
update_size
(
pb
,
pos
);
}
}
static
int
mov_write_tmcd_tag
(
AVIOContext
*
pb
,
MOVTrack
*
track
)
{
int64_t
pos
=
avio_tell
(
pb
);
int
frame_duration
=
track
->
enc
->
time_base
.
num
;
int
nb_frames
=
(
track
->
timescale
+
frame_duration
/
2
)
/
frame_duration
;
avio_wb32
(
pb
,
0
);
/* size */
ffio_wfourcc
(
pb
,
"tmcd"
);
/* Data format */
avio_wb32
(
pb
,
0
);
/* Reserved */
avio_wb32
(
pb
,
1
);
/* Data reference index */
avio_wb32
(
pb
,
0
);
/* Flags */
avio_wb32
(
pb
,
track
->
timecode_flags
);
/* Flags (timecode) */
avio_wb32
(
pb
,
track
->
timescale
);
/* Timescale */
avio_wb32
(
pb
,
frame_duration
);
/* Frame duration */
avio_w8
(
pb
,
nb_frames
);
/* Number of frames */
avio_wb24
(
pb
,
0
);
/* Reserved */
/* TODO: source reference string */
return
update_size
(
pb
,
pos
);
}
static
int
mov_write_rtp_tag
(
AVIOContext
*
pb
,
MOVTrack
*
track
)
static
int
mov_write_rtp_tag
(
AVIOContext
*
pb
,
MOVTrack
*
track
)
{
{
int64_t
pos
=
avio_tell
(
pb
);
int64_t
pos
=
avio_tell
(
pb
);
...
@@ -1130,6 +1150,8 @@ static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
...
@@ -1130,6 +1150,8 @@ static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
mov_write_subtitle_tag
(
pb
,
track
);
mov_write_subtitle_tag
(
pb
,
track
);
else
if
(
track
->
enc
->
codec_tag
==
MKTAG
(
'r'
,
't'
,
'p'
,
' '
))
else
if
(
track
->
enc
->
codec_tag
==
MKTAG
(
'r'
,
't'
,
'p'
,
' '
))
mov_write_rtp_tag
(
pb
,
track
);
mov_write_rtp_tag
(
pb
,
track
);
else
if
(
track
->
enc
->
codec_tag
==
MKTAG
(
't'
,
'm'
,
'c'
,
'd'
))
mov_write_tmcd_tag
(
pb
,
track
);
return
update_size
(
pb
,
pos
);
return
update_size
(
pb
,
pos
);
}
}
...
@@ -1262,9 +1284,32 @@ static int mov_write_nmhd_tag(AVIOContext *pb)
...
@@ -1262,9 +1284,32 @@ static int mov_write_nmhd_tag(AVIOContext *pb)
return
12
;
return
12
;
}
}
static
int
mov_write_
gmhd_tag
(
AVIOContext
*
pb
)
static
int
mov_write_
tcmi_tag
(
AVIOContext
*
pb
,
MOVTrack
*
track
)
{
{
avio_wb32
(
pb
,
0x4C
);
/* size */
int64_t
pos
=
avio_tell
(
pb
);
const
char
*
font
=
"Lucida Grande"
;
avio_wb32
(
pb
,
0
);
/* size */
ffio_wfourcc
(
pb
,
"tcmi"
);
/* timecode media information atom */
avio_wb32
(
pb
,
0
);
/* version & flags */
avio_wb16
(
pb
,
0
);
/* text font */
avio_wb16
(
pb
,
0
);
/* text face */
avio_wb16
(
pb
,
12
);
/* text size */
avio_wb16
(
pb
,
0
);
/* (unknown, not in the QT specs...) */
avio_wb16
(
pb
,
0x0000
);
/* text color (red) */
avio_wb16
(
pb
,
0x0000
);
/* text color (green) */
avio_wb16
(
pb
,
0x0000
);
/* text color (blue) */
avio_wb16
(
pb
,
0xffff
);
/* background color (red) */
avio_wb16
(
pb
,
0xffff
);
/* background color (green) */
avio_wb16
(
pb
,
0xffff
);
/* background color (blue) */
avio_w8
(
pb
,
strlen
(
font
));
/* font len (part of the pascal string) */
avio_write
(
pb
,
font
,
strlen
(
font
));
/* font name */
return
update_size
(
pb
,
pos
);
}
static
int
mov_write_gmhd_tag
(
AVIOContext
*
pb
,
MOVTrack
*
track
)
{
int64_t
pos
=
avio_tell
(
pb
);
avio_wb32
(
pb
,
0
);
/* size */
ffio_wfourcc
(
pb
,
"gmhd"
);
ffio_wfourcc
(
pb
,
"gmhd"
);
avio_wb32
(
pb
,
0x18
);
/* gmin size */
avio_wb32
(
pb
,
0x18
);
/* gmin size */
ffio_wfourcc
(
pb
,
"gmin"
);
/* generic media info */
ffio_wfourcc
(
pb
,
"gmin"
);
/* generic media info */
...
@@ -1295,7 +1340,14 @@ static int mov_write_gmhd_tag(AVIOContext *pb)
...
@@ -1295,7 +1340,14 @@ static int mov_write_gmhd_tag(AVIOContext *pb)
avio_wb32
(
pb
,
0x00004000
);
avio_wb32
(
pb
,
0x00004000
);
avio_wb16
(
pb
,
0x0000
);
avio_wb16
(
pb
,
0x0000
);
return
0x4C
;
if
(
track
->
enc
->
codec_tag
==
MKTAG
(
't'
,
'm'
,
'c'
,
'd'
))
{
int64_t
tmcd_pos
=
avio_tell
(
pb
);
avio_wb32
(
pb
,
0
);
/* size */
ffio_wfourcc
(
pb
,
"tmcd"
);
mov_write_tcmi_tag
(
pb
,
track
);
update_size
(
pb
,
tmcd_pos
);
}
return
update_size
(
pb
,
pos
);
}
}
static
int
mov_write_smhd_tag
(
AVIOContext
*
pb
)
static
int
mov_write_smhd_tag
(
AVIOContext
*
pb
)
...
@@ -1338,6 +1390,9 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track)
...
@@ -1338,6 +1390,9 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track)
if
(
track
->
tag
==
MKTAG
(
't'
,
'x'
,
'3'
,
'g'
))
hdlr_type
=
"sbtl"
;
if
(
track
->
tag
==
MKTAG
(
't'
,
'x'
,
'3'
,
'g'
))
hdlr_type
=
"sbtl"
;
else
hdlr_type
=
"text"
;
else
hdlr_type
=
"text"
;
descr
=
"SubtitleHandler"
;
descr
=
"SubtitleHandler"
;
}
else
if
(
track
->
enc
->
codec_tag
==
MKTAG
(
't'
,
'm'
,
'c'
,
'd'
))
{
hdlr_type
=
"tmcd"
;
descr
=
"TimeCodeHandler"
;
}
else
if
(
track
->
enc
->
codec_tag
==
MKTAG
(
'r'
,
't'
,
'p'
,
' '
))
{
}
else
if
(
track
->
enc
->
codec_tag
==
MKTAG
(
'r'
,
't'
,
'p'
,
' '
))
{
hdlr_type
=
"hint"
;
hdlr_type
=
"hint"
;
descr
=
"HintHandler"
;
descr
=
"HintHandler"
;
...
@@ -1389,8 +1444,10 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
...
@@ -1389,8 +1444,10 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
else
if
(
track
->
enc
->
codec_type
==
AVMEDIA_TYPE_AUDIO
)
else
if
(
track
->
enc
->
codec_type
==
AVMEDIA_TYPE_AUDIO
)
mov_write_smhd_tag
(
pb
);
mov_write_smhd_tag
(
pb
);
else
if
(
track
->
enc
->
codec_type
==
AVMEDIA_TYPE_SUBTITLE
)
{
else
if
(
track
->
enc
->
codec_type
==
AVMEDIA_TYPE_SUBTITLE
)
{
if
(
track
->
tag
==
MKTAG
(
't'
,
'e'
,
'x'
,
't'
))
mov_write_gmhd_tag
(
pb
);
if
(
track
->
tag
==
MKTAG
(
't'
,
'e'
,
'x'
,
't'
))
mov_write_gmhd_tag
(
pb
,
track
);
else
mov_write_nmhd_tag
(
pb
);
else
mov_write_nmhd_tag
(
pb
);
}
else
if
(
track
->
tag
==
MKTAG
(
't'
,
'm'
,
'c'
,
'd'
))
{
mov_write_gmhd_tag
(
pb
,
track
);
}
else
if
(
track
->
tag
==
MKTAG
(
'r'
,
't'
,
'p'
,
' '
))
{
}
else
if
(
track
->
tag
==
MKTAG
(
'r'
,
't'
,
'p'
,
' '
))
{
mov_write_hmhd_tag
(
pb
);
mov_write_hmhd_tag
(
pb
);
}
}
...
@@ -2147,6 +2204,14 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
...
@@ -2147,6 +2204,14 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
mov
->
tracks
[
mov
->
tracks
[
i
].
src_track
].
track_id
;
mov
->
tracks
[
mov
->
tracks
[
i
].
src_track
].
track_id
;
}
}
}
}
for
(
i
=
0
;
i
<
mov
->
nb_streams
;
i
++
)
{
if
(
mov
->
tracks
[
i
].
tag
==
MKTAG
(
't'
,
'm'
,
'c'
,
'd'
))
{
int
src_trk
=
mov
->
tracks
[
i
].
src_track
;
mov
->
tracks
[
src_trk
].
tref_tag
=
mov
->
tracks
[
i
].
tag
;
mov
->
tracks
[
src_trk
].
tref_id
=
mov
->
tracks
[
i
].
track_id
;
mov
->
tracks
[
i
].
track_duration
=
mov
->
tracks
[
src_trk
].
track_duration
;
}
}
mov_write_mvhd_tag
(
pb
,
mov
);
mov_write_mvhd_tag
(
pb
,
mov
);
if
(
mov
->
mode
!=
MODE_MOV
&&
!
mov
->
iods_skip
)
if
(
mov
->
mode
!=
MODE_MOV
&&
!
mov
->
iods_skip
)
...
@@ -3151,12 +3216,48 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
...
@@ -3151,12 +3216,48 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum)
}
}
}
}
static
int
mov_create_timecode_track
(
AVFormatContext
*
s
,
int
index
,
int
src_index
,
const
char
*
tcstr
)
{
MOVMuxContext
*
mov
=
s
->
priv_data
;
MOVTrack
*
track
=
&
mov
->
tracks
[
index
];
AVStream
*
src_st
=
s
->
streams
[
src_index
];
AVTimecode
tc
;
AVPacket
pkt
=
{.
stream_index
=
index
,
.
flags
=
AV_PKT_FLAG_KEY
,
.
size
=
4
};
AVRational
rate
=
{
src_st
->
codec
->
time_base
.
den
,
src_st
->
codec
->
time_base
.
num
};
/* compute the frame number */
int
ret
=
av_timecode_init_from_string
(
&
tc
,
rate
,
tcstr
,
s
);
if
(
ret
<
0
)
return
ret
;
/* tmcd track based on video stream */
track
->
mode
=
mov
->
mode
;
track
->
tag
=
MKTAG
(
't'
,
'm'
,
'c'
,
'd'
);
track
->
src_track
=
src_index
;
track
->
timescale
=
src_st
->
codec
->
time_base
.
den
;
if
(
tc
.
flags
&
AV_TIMECODE_FLAG_DROPFRAME
)
track
->
timecode_flags
|=
MOV_TIMECODE_FLAG_DROPFRAME
;
/* encode context: tmcd data stream */
track
->
enc
=
avcodec_alloc_context3
(
NULL
);
track
->
enc
->
codec_type
=
AVMEDIA_TYPE_DATA
;
track
->
enc
->
codec_tag
=
track
->
tag
;
track
->
enc
->
time_base
=
src_st
->
codec
->
time_base
;
/* the tmcd track just contains one packet with the frame number */
pkt
.
data
=
av_malloc
(
pkt
.
size
);
AV_WB32
(
pkt
.
data
,
tc
.
start
);
ret
=
ff_mov_write_packet
(
s
,
&
pkt
);
av_free
(
pkt
.
data
);
return
ret
;
}
static
int
mov_write_header
(
AVFormatContext
*
s
)
static
int
mov_write_header
(
AVFormatContext
*
s
)
{
{
AVIOContext
*
pb
=
s
->
pb
;
AVIOContext
*
pb
=
s
->
pb
;
MOVMuxContext
*
mov
=
s
->
priv_data
;
MOVMuxContext
*
mov
=
s
->
priv_data
;
AVDictionaryEntry
*
t
;
AVDictionaryEntry
*
t
,
*
global_tcr
=
av_dict_get
(
s
->
metadata
,
"timecode"
,
NULL
,
0
)
;
int
i
,
hint_track
=
0
;
int
i
,
hint_track
=
0
,
tmcd_track
=
0
;
/* Set the FRAGMENT flag if any of the fragmentation methods are
/* Set the FRAGMENT flag if any of the fragmentation methods are
* enabled. */
* enabled. */
...
@@ -3213,6 +3314,17 @@ static int mov_write_header(AVFormatContext *s)
...
@@ -3213,6 +3314,17 @@ static int mov_write_header(AVFormatContext *s)
}
}
}
}
if
(
mov
->
mode
==
MODE_MOV
)
{
/* Add a tmcd track for each video stream with a timecode */
tmcd_track
=
mov
->
nb_streams
;
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
AVStream
*
st
=
s
->
streams
[
i
];
if
(
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_VIDEO
&&
(
global_tcr
||
av_dict_get
(
st
->
metadata
,
"timecode"
,
NULL
,
0
)))
mov
->
nb_streams
++
;
}
}
mov
->
tracks
=
av_mallocz
(
mov
->
nb_streams
*
sizeof
(
*
mov
->
tracks
));
mov
->
tracks
=
av_mallocz
(
mov
->
nb_streams
*
sizeof
(
*
mov
->
tracks
));
if
(
!
mov
->
tracks
)
if
(
!
mov
->
tracks
)
return
AVERROR
(
ENOMEM
);
return
AVERROR
(
ENOMEM
);
...
@@ -3336,6 +3448,24 @@ static int mov_write_header(AVFormatContext *s)
...
@@ -3336,6 +3448,24 @@ static int mov_write_header(AVFormatContext *s)
}
}
}
}
if
(
mov
->
mode
==
MODE_MOV
)
{
/* Initialize the tmcd tracks */
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
AVStream
*
st
=
s
->
streams
[
i
];
t
=
global_tcr
;
if
(
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_VIDEO
)
{
if
(
!
t
)
t
=
av_dict_get
(
st
->
metadata
,
"timecode"
,
NULL
,
0
);
if
(
!
t
)
continue
;
if
(
mov_create_timecode_track
(
s
,
tmcd_track
,
i
,
t
->
value
)
<
0
)
goto
error
;
tmcd_track
++
;
}
}
}
avio_flush
(
pb
);
avio_flush
(
pb
);
if
(
mov
->
flags
&
FF_MOV_FLAG_ISML
)
if
(
mov
->
flags
&
FF_MOV_FLAG_ISML
)
...
@@ -3401,6 +3531,8 @@ static int mov_write_trailer(AVFormatContext *s)
...
@@ -3401,6 +3531,8 @@ static int mov_write_trailer(AVFormatContext *s)
for
(
i
=
0
;
i
<
mov
->
nb_streams
;
i
++
)
{
for
(
i
=
0
;
i
<
mov
->
nb_streams
;
i
++
)
{
if
(
mov
->
tracks
[
i
].
tag
==
MKTAG
(
'r'
,
't'
,
'p'
,
' '
))
if
(
mov
->
tracks
[
i
].
tag
==
MKTAG
(
'r'
,
't'
,
'p'
,
' '
))
ff_mov_close_hinting
(
&
mov
->
tracks
[
i
]);
ff_mov_close_hinting
(
&
mov
->
tracks
[
i
]);
else
if
(
mov
->
tracks
[
i
].
tag
==
MKTAG
(
't'
,
'm'
,
'c'
,
'd'
))
av_freep
(
&
mov
->
tracks
[
i
].
enc
);
if
(
mov
->
flags
&
FF_MOV_FLAG_FRAGMENT
&&
if
(
mov
->
flags
&
FF_MOV_FLAG_FRAGMENT
&&
mov
->
tracks
[
i
].
vc1_info
.
struct_offset
&&
s
->
pb
->
seekable
)
{
mov
->
tracks
[
i
].
vc1_info
.
struct_offset
&&
s
->
pb
->
seekable
)
{
int64_t
off
=
avio_tell
(
pb
);
int64_t
off
=
avio_tell
(
pb
);
...
...
libavformat/movenc.h
View file @
9fb2e234
...
@@ -87,6 +87,10 @@ typedef struct MOVIndex {
...
@@ -87,6 +87,10 @@ typedef struct MOVIndex {
#define MOV_TRACK_CTTS 0x0001
#define MOV_TRACK_CTTS 0x0001
#define MOV_TRACK_STPS 0x0002
#define MOV_TRACK_STPS 0x0002
uint32_t
flags
;
uint32_t
flags
;
#define MOV_TIMECODE_FLAG_DROPFRAME 0x0001
#define MOV_TIMECODE_FLAG_24HOURSMAX 0x0002
#define MOV_TIMECODE_FLAG_ALLOWNEGATIVE 0x0004
uint32_t
timecode_flags
;
int
language
;
int
language
;
int
track_id
;
int
track_id
;
int
tag
;
///< stsd fourcc
int
tag
;
///< stsd fourcc
...
@@ -102,7 +106,7 @@ typedef struct MOVIndex {
...
@@ -102,7 +106,7 @@ typedef struct MOVIndex {
int64_t
start_dts
;
int64_t
start_dts
;
int
hint_track
;
///< the track that hints this track, -1 if no hint track is set
int
hint_track
;
///< the track that hints this track, -1 if no hint track is set
int
src_track
;
///< the track that this hint track describes
int
src_track
;
///< the track that this hint
(or tmcd)
track describes
AVFormatContext
*
rtp_ctx
;
///< the format context for the hinting rtp muxer
AVFormatContext
*
rtp_ctx
;
///< the format context for the hinting rtp muxer
uint32_t
prev_rtp_ts
;
uint32_t
prev_rtp_ts
;
int64_t
cur_rtp_ts_unwrapped
;
int64_t
cur_rtp_ts_unwrapped
;
...
...
tests/ref/lavf/mov
View file @
9fb2e234
484aeef3be3eb4deef05c83bdc2dd484 *./tests/data/lavf/lavf.mov
484aeef3be3eb4deef05c83bdc2dd484 *./tests/data/lavf/lavf.mov
367346 ./tests/data/lavf/lavf.mov
367346 ./tests/data/lavf/lavf.mov
./tests/data/lavf/lavf.mov CRC=0x2f6a9b26
./tests/data/lavf/lavf.mov CRC=0x2f6a9b26
305a68397e3cdb505704841fedcdc352
*./tests/data/lavf/lavf.mov
21b992f6a677f971dfd685cc055a2b0a
*./tests/data/lavf/lavf.mov
35
7845
./tests/data/lavf/lavf.mov
35
8463
./tests/data/lavf/lavf.mov
./tests/data/lavf/lavf.mov CRC=0x2f6a9b26
./tests/data/lavf/lavf.mov CRC=0x2f6a9b26
6e047bce400f2c4a840f783dee1ae030
*./tests/data/lavf/lavf.mov
f1e80a52983775ea27dda0590b46e17a
*./tests/data/lavf/lavf.mov
367
275
./tests/data/lavf/lavf.mov
367
893
./tests/data/lavf/lavf.mov
./tests/data/lavf/lavf.mov CRC=0xab307eb9
./tests/data/lavf/lavf.mov CRC=0xab307eb9
305a68397e3cdb505704841fedcdc352 *./tests/data/lavf/lavf.mov
305a68397e3cdb505704841fedcdc352 *./tests/data/lavf/lavf.mov
357845 ./tests/data/lavf/lavf.mov
357845 ./tests/data/lavf/lavf.mov
...
...
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