|
|
|
/*
|
|
|
|
* MOV, 3GP, MP4 muxer
|
|
|
|
* Copyright (c) 2003 Thomas Raivio
|
|
|
|
* Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
|
|
|
|
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
|
|
|
|
*
|
|
|
|
* This file is part of FFmpeg.
|
|
|
|
*
|
|
|
|
* FFmpeg 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.
|
|
|
|
*
|
|
|
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef AVFORMAT_MOVENC_H
|
|
|
|
#define AVFORMAT_MOVENC_H
|
|
|
|
|
|
|
|
#include "avformat.h"
|
|
|
|
#include "movenccenc.h"
|
|
|
|
|
|
|
|
#define MOV_FRAG_INFO_ALLOC_INCREMENT 64
|
|
|
|
#define MOV_INDEX_CLUSTER_SIZE 1024
|
|
|
|
#define MOV_TIMESCALE 1000
|
|
|
|
|
|
|
|
#define RTP_MAX_PACKET_SIZE 1450
|
|
|
|
|
|
|
|
#define MODE_MP4 0x01
|
|
|
|
#define MODE_MOV 0x02
|
|
|
|
#define MODE_3GP 0x04
|
|
|
|
#define MODE_PSP 0x08 // example working PSP command line:
|
|
|
|
// ffmpeg -i testinput.avi -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4
|
|
|
|
#define MODE_3G2 0x10
|
|
|
|
#define MODE_IPOD 0x20
|
|
|
|
#define MODE_ISM 0x40
|
|
|
|
#define MODE_F4V 0x80
|
|
|
|
|
|
|
|
typedef struct MOVIentry {
|
|
|
|
uint64_t pos;
|
|
|
|
int64_t dts;
|
|
|
|
unsigned int size;
|
|
|
|
unsigned int samples_in_chunk;
|
|
|
|
unsigned int chunkNum; ///< Chunk number if the current entry is a chunk start otherwise 0
|
|
|
|
unsigned int entries;
|
|
|
|
int cts;
|
|
|
|
#define MOV_SYNC_SAMPLE 0x0001
|
|
|
|
#define MOV_PARTIAL_SYNC_SAMPLE 0x0002
|
|
|
|
uint32_t flags;
|
|
|
|
} MOVIentry;
|
|
|
|
|
|
|
|
typedef struct HintSample {
|
|
|
|
uint8_t *data;
|
|
|
|
int size;
|
|
|
|
int sample_number;
|
|
|
|
int offset;
|
|
|
|
int own_data;
|
|
|
|
} HintSample;
|
|
|
|
|
|
|
|
typedef struct HintSampleQueue {
|
|
|
|
int size;
|
|
|
|
int len;
|
|
|
|
HintSample *samples;
|
|
|
|
} HintSampleQueue;
|
|
|
|
|
|
|
|
typedef struct MOVFragmentInfo {
|
|
|
|
int64_t offset;
|
|
|
|
int64_t time;
|
|
|
|
int64_t duration;
|
|
|
|
int64_t tfrf_offset;
|
|
|
|
int size;
|
|
|
|
} MOVFragmentInfo;
|
|
|
|
|
|
|
|
typedef struct MOVTrack {
|
|
|
|
int mode;
|
|
|
|
int entry;
|
|
|
|
unsigned timescale;
|
|
|
|
uint64_t time;
|
|
|
|
int64_t track_duration;
|
|
|
|
int last_sample_is_subtitle_end;
|
|
|
|
long sample_count;
|
|
|
|
long sample_size;
|
|
|
|
long chunkCount;
|
|
|
|
int has_keyframes;
|
|
|
|
#define MOV_TRACK_CTTS 0x0001
|
|
|
|
#define MOV_TRACK_STPS 0x0002
|
|
|
|
#define MOV_TRACK_ENABLED 0x0004
|
|
|
|
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 track_id;
|
|
|
|
int tag; ///< stsd fourcc
|
|
|
|
AVStream *st;
|
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
11 years ago
|
|
|
AVCodecParameters *par;
|
|
|
|
int multichannel_as_mono;
|
|
|
|
|
|
|
|
int vos_len;
|
|
|
|
uint8_t *vos_data;
|
|
|
|
MOVIentry *cluster;
|
|
|
|
unsigned cluster_capacity;
|
|
|
|
int audio_vbr;
|
|
|
|
int height; ///< active picture (w/o VBI) height for D-10/IMX
|
|
|
|
uint32_t tref_tag;
|
|
|
|
int tref_id; ///< trackID of the referenced track
|
|
|
|
int64_t start_dts;
|
|
|
|
int64_t start_cts;
|
|
|
|
int64_t end_pts;
|
|
|
|
int end_reliable;
|
|
|
|
|
|
|
|
int hint_track; ///< the track that hints this track, -1 if no hint track is set
|
|
|
|
int src_track; ///< the track that this hint (or tmcd) track describes
|
|
|
|
AVFormatContext *rtp_ctx; ///< the format context for the hinting rtp muxer
|
|
|
|
uint32_t prev_rtp_ts;
|
|
|
|
int64_t cur_rtp_ts_unwrapped;
|
|
|
|
uint32_t max_packet_size;
|
|
|
|
|
|
|
|
int64_t default_duration;
|
|
|
|
uint32_t default_sample_flags;
|
|
|
|
uint32_t default_size;
|
|
|
|
|
|
|
|
HintSampleQueue sample_queue;
|
|
|
|
|
|
|
|
AVIOContext *mdat_buf;
|
|
|
|
int64_t data_offset;
|
|
|
|
int64_t frag_start;
|
|
|
|
int frag_discont;
|
|
|
|
int entries_flushed;
|
|
|
|
|
|
|
|
int nb_frag_info;
|
|
|
|
MOVFragmentInfo *frag_info;
|
|
|
|
unsigned frag_info_capacity;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
int first_packet_seq;
|
|
|
|
int first_packet_entry;
|
|
|
|
int first_packet_seen;
|
|
|
|
int first_frag_written;
|
|
|
|
int packet_seq;
|
|
|
|
int packet_entry;
|
|
|
|
int slices;
|
|
|
|
} vc1_info;
|
|
|
|
|
|
|
|
void *eac3_priv;
|
|
|
|
|
|
|
|
MOVMuxCencContext cenc;
|
|
|
|
|
|
|
|
uint32_t palette[AVPALETTE_COUNT];
|
|
|
|
int pal_done;
|
|
|
|
|
|
|
|
int is_unaligned_qt_rgb;
|
|
|
|
} MOVTrack;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
MOV_ENC_NONE = 0,
|
|
|
|
MOV_ENC_CENC_AES_CTR,
|
|
|
|
} MOVEncryptionScheme;
|
|
|
|
|
|
|
|
typedef struct MOVMuxContext {
|
|
|
|
const AVClass *av_class;
|
|
|
|
int mode;
|
|
|
|
int64_t time;
|
|
|
|
int nb_streams;
|
|
|
|
int nb_meta_tmcd; ///< number of new created tmcd track based on metadata (aka not data copy)
|
|
|
|
int chapter_track; ///< qt chapter track number
|
|
|
|
int64_t mdat_pos;
|
|
|
|
uint64_t mdat_size;
|
|
|
|
MOVTrack *tracks;
|
|
|
|
|
|
|
|
int flags;
|
|
|
|
int rtp_flags;
|
|
|
|
|
|
|
|
int iods_skip;
|
|
|
|
int iods_video_profile;
|
|
|
|
int iods_audio_profile;
|
|
|
|
|
|
|
|
int moov_written;
|
|
|
|
int fragments;
|
|
|
|
int max_fragment_duration;
|
|
|
|
int min_fragment_duration;
|
|
|
|
int max_fragment_size;
|
|
|
|
int ism_lookahead;
|
movenc: Buffer the mdat for the initial moov fragment, too
This allows writing QuickTime-compatible fragmented mp4 (with
a non-empty moov atom) to a non-seekable output.
This buffers the mdat for the initial fragment just as it does
for all normal fragments, too. Previously, the resulting
atom structure was mdat,moov, moof,mdat ..., while it now
is moov,mdat, moof,mdat.
Signed-off-by: Martin Storsjö <martin@martin.st>
13 years ago
|
|
|
AVIOContext *mdat_buf;
|
|
|
|
int first_trun;
|
|
|
|
|
|
|
|
int video_track_timescale;
|
|
|
|
|
|
|
|
int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise
|
|
|
|
int64_t reserved_header_pos;
|
|
|
|
|
|
|
|
char *major_brand;
|
|
|
|
|
|
|
|
int per_stream_grouping;
|
|
|
|
AVFormatContext *fc;
|
|
|
|
|
|
|
|
int use_editlist;
|
|
|
|
float gamma;
|
|
|
|
|
|
|
|
int frag_interleave;
|
|
|
|
int missing_duration_warned;
|
|
|
|
|
|
|
|
char *encryption_scheme_str;
|
|
|
|
MOVEncryptionScheme encryption_scheme;
|
|
|
|
uint8_t *encryption_key;
|
|
|
|
int encryption_key_len;
|
|
|
|
uint8_t *encryption_kid;
|
|
|
|
int encryption_kid_len;
|
|
|
|
|
|
|
|
int need_rewrite_extradata;
|
|
|
|
|
|
|
|
int use_stream_ids_as_track_ids;
|
|
|
|
int track_ids_ok;
|
|
|
|
int write_tmcd;
|
|
|
|
} MOVMuxContext;
|
|
|
|
|
|
|
|
#define FF_MOV_FLAG_RTP_HINT (1 << 0)
|
|
|
|
#define FF_MOV_FLAG_FRAGMENT (1 << 1)
|
|
|
|
#define FF_MOV_FLAG_EMPTY_MOOV (1 << 2)
|
|
|
|
#define FF_MOV_FLAG_FRAG_KEYFRAME (1 << 3)
|
|
|
|
#define FF_MOV_FLAG_SEPARATE_MOOF (1 << 4)
|
|
|
|
#define FF_MOV_FLAG_FRAG_CUSTOM (1 << 5)
|
|
|
|
#define FF_MOV_FLAG_ISML (1 << 6)
|
|
|
|
#define FF_MOV_FLAG_FASTSTART (1 << 7)
|
|
|
|
#define FF_MOV_FLAG_OMIT_TFHD_OFFSET (1 << 8)
|
|
|
|
#define FF_MOV_FLAG_DISABLE_CHPL (1 << 9)
|
|
|
|
#define FF_MOV_FLAG_DEFAULT_BASE_MOOF (1 << 10)
|
|
|
|
#define FF_MOV_FLAG_DASH (1 << 11)
|
|
|
|
#define FF_MOV_FLAG_FRAG_DISCONT (1 << 12)
|
movenc: Add an option for delaying writing the moov with empty_moov
This delays writing the moov until the first fragment is written,
or can be flushed by the caller explicitly when wanted. If the first
sample in all streams is available at this point, we can write
a proper editlist at this point, allowing streams to start at
something else than dts=0. For AC3 and DNXHD, a packet is
needed in order to write the moov header properly.
This isn't added to the normal behaviour for empty_moov, since
the behaviour that ftyp+moov is written during avformat_write_header
would be changed. Callers that split the output stream into header+segments
(either by flushing manually, with the custom_frag flag set, or by
just differentiating between data written during avformat_write_header
and the rest) will need to be adjusted to take this option into use.
For handling streams that start at something else than dts=0, an
alternative would be to use different kinds of heuristics for
guessing the start dts (using AVCodecContext delay or has_b_frames
together with the frame rate), but this is not reliable and doesn't
necessarily work well with stream copy, and wouldn't work for getting
the right initialization data for AC3 or DNXHD either.
Signed-off-by: Martin Storsjö <martin@martin.st>
10 years ago
|
|
|
#define FF_MOV_FLAG_DELAY_MOOV (1 << 13)
|
|
|
|
#define FF_MOV_FLAG_GLOBAL_SIDX (1 << 14)
|
|
|
|
#define FF_MOV_FLAG_WRITE_COLR (1 << 15)
|
|
|
|
#define FF_MOV_FLAG_WRITE_GAMA (1 << 16)
|
|
|
|
#define FF_MOV_FLAG_USE_MDTA (1 << 17)
|
|
|
|
#define FF_MOV_FLAG_SKIP_TRAILER (1 << 18)
|
|
|
|
|
|
|
|
int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
|
|
|
|
|
|
|
|
int ff_mov_init_hinting(AVFormatContext *s, int index, int src_index);
|
|
|
|
int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
|
|
|
|
int track_index, int sample,
|
|
|
|
uint8_t *sample_data, int sample_size);
|
|
|
|
void ff_mov_close_hinting(MOVTrack *track);
|
|
|
|
|
|
|
|
#endif /* AVFORMAT_MOVENC_H */
|