3 * Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at free dot fr>
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/crc.h"
23 #include "libavcodec/xiph.h"
24 #include "libavcodec/bytestream.h"
25 #include "libavcodec/flac.h"
31 unsigned page_counter
;
34 /** for theora granule */
41 static void ogg_update_checksum(AVFormatContext
*s
, int64_t crc_offset
)
43 int64_t pos
= url_ftell(s
->pb
);
44 uint32_t checksum
= get_checksum(s
->pb
);
45 url_fseek(s
->pb
, crc_offset
, SEEK_SET
);
46 put_be32(s
->pb
, checksum
);
47 url_fseek(s
->pb
, pos
, SEEK_SET
);
50 static int ogg_write_page(AVFormatContext
*s
, const uint8_t *data
, int size
,
51 int64_t granule
, int stream_index
, int flags
)
53 OGGStreamContext
*oggstream
= s
->streams
[stream_index
]->priv_data
;
57 if (size
>= 255*255) {
60 } else if (oggstream
->eos
)
63 page_segments
= FFMIN((size
/255)+!!size
, 255);
65 init_checksum(s
->pb
, ff_crc04C11DB7_update
, 0);
66 put_tag(s
->pb
, "OggS");
68 put_byte(s
->pb
, flags
);
69 put_le64(s
->pb
, granule
);
70 put_le32(s
->pb
, stream_index
);
71 put_le32(s
->pb
, oggstream
->page_counter
++);
72 crc_offset
= url_ftell(s
->pb
);
73 put_le32(s
->pb
, 0); // crc
74 put_byte(s
->pb
, page_segments
);
75 for (i
= 0; i
< page_segments
-1; i
++)
78 put_byte(s
->pb
, size
- (page_segments
-1)*255);
79 put_buffer(s
->pb
, data
, size
);
81 ogg_update_checksum(s
, crc_offset
);
82 put_flush_packet(s
->pb
);
86 static int ogg_build_flac_headers(AVCodecContext
*avctx
,
87 OGGStreamContext
*oggstream
, int bitexact
)
89 const char *vendor
= bitexact
? "ffmpeg" : LIBAVFORMAT_IDENT
;
90 enum FLACExtradataFormat format
;
94 if (!ff_flac_is_extradata_valid(avctx
, &format
, &streaminfo
))
97 // first packet: STREAMINFO
98 oggstream
->header_len
[0] = 51;
99 oggstream
->header
[0] = av_mallocz(51); // per ogg flac specs
100 p
= oggstream
->header
[0];
102 return AVERROR_NOMEM
;
103 bytestream_put_byte(&p
, 0x7F);
104 bytestream_put_buffer(&p
, "FLAC", 4);
105 bytestream_put_byte(&p
, 1); // major version
106 bytestream_put_byte(&p
, 0); // minor version
107 bytestream_put_be16(&p
, 1); // headers packets without this one
108 bytestream_put_buffer(&p
, "fLaC", 4);
109 bytestream_put_byte(&p
, 0x00); // streaminfo
110 bytestream_put_be24(&p
, 34);
111 bytestream_put_buffer(&p
, streaminfo
, FLAC_STREAMINFO_SIZE
);
113 // second packet: VorbisComment
114 oggstream
->header_len
[1] = 1+3+4+strlen(vendor
)+4;
115 oggstream
->header
[1] = av_mallocz(oggstream
->header_len
[1]);
116 p
= oggstream
->header
[1];
118 return AVERROR_NOMEM
;
119 bytestream_put_byte(&p
, 0x84); // last metadata block and vorbis comment
120 bytestream_put_be24(&p
, oggstream
->header_len
[1] - 4);
121 bytestream_put_le32(&p
, strlen(vendor
));
122 bytestream_put_buffer(&p
, vendor
, strlen(vendor
));
123 bytestream_put_le32(&p
, 0); // user comment list length
128 static int ogg_write_header(AVFormatContext
*s
)
130 OGGStreamContext
*oggstream
;
132 for (i
= 0; i
< s
->nb_streams
; i
++) {
133 AVStream
*st
= s
->streams
[i
];
134 if (st
->codec
->codec_type
== CODEC_TYPE_AUDIO
)
135 av_set_pts_info(st
, 64, 1, st
->codec
->sample_rate
);
136 else if (st
->codec
->codec_type
== CODEC_TYPE_VIDEO
)
137 av_set_pts_info(st
, 64, st
->codec
->time_base
.num
, st
->codec
->time_base
.den
);
138 if (st
->codec
->codec_id
!= CODEC_ID_VORBIS
&&
139 st
->codec
->codec_id
!= CODEC_ID_THEORA
&&
140 st
->codec
->codec_id
!= CODEC_ID_FLAC
) {
141 av_log(s
, AV_LOG_ERROR
, "Unsupported codec id in stream %d\n", i
);
145 if (!st
->codec
->extradata
|| !st
->codec
->extradata_size
) {
146 av_log(s
, AV_LOG_ERROR
, "No extradata present\n");
149 oggstream
= av_mallocz(sizeof(*oggstream
));
150 st
->priv_data
= oggstream
;
151 if (st
->codec
->codec_id
== CODEC_ID_FLAC
) {
152 int err
= ogg_build_flac_headers(st
->codec
, oggstream
,
153 st
->codec
->flags
& CODEC_FLAG_BITEXACT
);
155 av_log(s
, AV_LOG_ERROR
, "Error writing FLAC headers\n");
156 av_freep(&st
->priv_data
);
160 if (ff_split_xiph_headers(st
->codec
->extradata
, st
->codec
->extradata_size
,
161 st
->codec
->codec_id
== CODEC_ID_VORBIS
? 30 : 42,
162 oggstream
->header
, oggstream
->header_len
) < 0) {
163 av_log(s
, AV_LOG_ERROR
, "Extradata corrupted\n");
164 av_freep(&st
->priv_data
);
167 if (st
->codec
->codec_id
== CODEC_ID_THEORA
) {
168 /** KFGSHIFT is the width of the less significant section of the granule position
169 The less significant section is the frame count since the last keyframe */
170 oggstream
->kfgshift
= ((oggstream
->header
[0][40]&3)<<3)|(oggstream
->header
[0][41]>>5);
171 oggstream
->vrev
= oggstream
->header
[0][9];
172 av_log(s
, AV_LOG_DEBUG
, "theora kfgshift %d, vrev %d\n",
173 oggstream
->kfgshift
, oggstream
->vrev
);
177 for (i
= 0; i
< 3; i
++) {
178 for (j
= 0; j
< s
->nb_streams
; j
++) {
179 AVStream
*st
= s
->streams
[j
];
180 OGGStreamContext
*oggstream
= st
->priv_data
;
181 if (oggstream
&& oggstream
->header_len
[i
]) {
182 ogg_write_page(s
, oggstream
->header
[i
], oggstream
->header_len
[i
],
183 0, st
->index
, i
? 0 : 2); // bos
190 static int ogg_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
192 AVStream
*st
= s
->streams
[pkt
->stream_index
];
193 OGGStreamContext
*oggstream
= st
->priv_data
;
194 uint8_t *ptr
= pkt
->data
;
195 int ret
, size
= pkt
->size
;
198 if (st
->codec
->codec_id
== CODEC_ID_THEORA
) {
199 int64_t pts
= oggstream
->vrev
< 1 ? pkt
->pts
: pkt
->pts
+ pkt
->duration
;
201 if (pkt
->flags
& PKT_FLAG_KEY
)
202 oggstream
->last_kf_pts
= pts
;
203 pframe_count
= pts
- oggstream
->last_kf_pts
;
204 // prevent frame count from overflow if key frame flag is not set
205 if (pframe_count
>= (1<<oggstream
->kfgshift
)) {
206 oggstream
->last_kf_pts
+= pframe_count
;
209 granule
= (oggstream
->last_kf_pts
<<oggstream
->kfgshift
) | pframe_count
;
211 granule
= pkt
->pts
+ pkt
->duration
;
212 oggstream
->duration
= granule
;
214 ret
= ogg_write_page(s
, ptr
, size
, granule
, pkt
->stream_index
, ptr
!= pkt
->data
);
215 ptr
+= ret
; size
-= ret
;
216 } while (size
> 0 || ret
== 255*255); // need to output a last nil page
221 static int ogg_compare_granule(AVFormatContext
*s
, AVPacket
*next
, AVPacket
*pkt
)
223 AVStream
*st2
= s
->streams
[next
->stream_index
];
224 AVStream
*st
= s
->streams
[pkt
->stream_index
];
226 int64_t next_granule
= av_rescale_q(next
->pts
+ next
->duration
,
227 st2
->time_base
, AV_TIME_BASE_Q
);
228 int64_t cur_granule
= av_rescale_q(pkt
->pts
+ pkt
->duration
,
229 st
->time_base
, AV_TIME_BASE_Q
);
230 return next_granule
> cur_granule
;
233 static int ogg_interleave_per_granule(AVFormatContext
*s
, AVPacket
*out
, AVPacket
*pkt
, int flush
)
236 int stream_count
= 0;
237 int streams
[MAX_STREAMS
] = {0};
241 ff_interleave_add_packet(s
, pkt
, ogg_compare_granule
);
244 pktl
= s
->packet_buffer
;
246 if (streams
[pktl
->pkt
.stream_index
] == 0)
248 streams
[pktl
->pkt
.stream_index
]++;
249 // need to buffer at least one packet to set eos flag
250 if (streams
[pktl
->pkt
.stream_index
] == 2)
255 if ((s
->nb_streams
== stream_count
&& interleaved
== stream_count
) ||
256 (flush
&& stream_count
)) {
257 pktl
= s
->packet_buffer
;
259 s
->packet_buffer
= pktl
->next
;
260 if (flush
&& streams
[out
->stream_index
] == 1) {
261 OGGStreamContext
*ogg
= s
->streams
[out
->stream_index
]->priv_data
;
264 if(!s
->packet_buffer
)
265 s
->packet_buffer_end
= NULL
;
267 if(s
->streams
[out
->stream_index
]->last_in_packet_buffer
== pktl
)
268 s
->streams
[out
->stream_index
]->last_in_packet_buffer
= NULL
;
278 static int ogg_write_trailer(AVFormatContext
*s
)
281 for (i
= 0; i
< s
->nb_streams
; i
++) {
282 AVStream
*st
= s
->streams
[i
];
283 OGGStreamContext
*oggstream
= st
->priv_data
;
284 if (st
->codec
->codec_id
== CODEC_ID_FLAC
) {
285 av_free(oggstream
->header
[0]);
286 av_free(oggstream
->header
[1]);
288 av_freep(&st
->priv_data
);
293 AVOutputFormat ogg_muxer
= {
295 NULL_IF_CONFIG_SMALL("Ogg"),
304 .interleave_packet
= ogg_interleave_per_granule
,