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"
29 unsigned page_counter
;
32 /** for theora granule */
39 static void ogg_update_checksum(AVFormatContext
*s
, offset_t crc_offset
)
41 offset_t pos
= url_ftell(s
->pb
);
42 uint32_t checksum
= get_checksum(s
->pb
);
43 url_fseek(s
->pb
, crc_offset
, SEEK_SET
);
44 put_be32(s
->pb
, checksum
);
45 url_fseek(s
->pb
, pos
, SEEK_SET
);
48 static int ogg_write_page(AVFormatContext
*s
, const uint8_t *data
, int size
,
49 int64_t granule
, int stream_index
, int flags
)
51 OGGStreamContext
*oggstream
= s
->streams
[stream_index
]->priv_data
;
55 if (size
>= 255*255) {
58 } else if (oggstream
->eos
)
61 page_segments
= FFMIN((size
/255)+!!size
, 255);
63 init_checksum(s
->pb
, ff_crc04C11DB7_update
, 0);
64 put_tag(s
->pb
, "OggS");
66 put_byte(s
->pb
, flags
);
67 put_le64(s
->pb
, granule
);
68 put_le32(s
->pb
, stream_index
);
69 put_le32(s
->pb
, oggstream
->page_counter
++);
70 crc_offset
= url_ftell(s
->pb
);
71 put_le32(s
->pb
, 0); // crc
72 put_byte(s
->pb
, page_segments
);
73 for (i
= 0; i
< page_segments
-1; i
++)
76 put_byte(s
->pb
, size
- (page_segments
-1)*255);
77 put_buffer(s
->pb
, data
, size
);
79 ogg_update_checksum(s
, crc_offset
);
80 put_flush_packet(s
->pb
);
84 static int ogg_build_flac_headers(const uint8_t *extradata
, int extradata_size
,
85 OGGStreamContext
*oggstream
, int bitexact
)
87 const char *vendor
= bitexact
? "ffmpeg" : LIBAVFORMAT_IDENT
;
89 if (extradata_size
!= 34)
91 oggstream
->header_len
[0] = 51;
92 oggstream
->header
[0] = av_mallocz(51); // per ogg flac specs
93 p
= oggstream
->header
[0];
94 bytestream_put_byte(&p
, 0x7F);
95 bytestream_put_buffer(&p
, "FLAC", 4);
96 bytestream_put_byte(&p
, 1); // major version
97 bytestream_put_byte(&p
, 0); // minor version
98 bytestream_put_be16(&p
, 1); // headers packets without this one
99 bytestream_put_buffer(&p
, "fLaC", 4);
100 bytestream_put_byte(&p
, 0x00); // streaminfo
101 bytestream_put_be24(&p
, 34);
102 bytestream_put_buffer(&p
, extradata
, 34);
103 oggstream
->header_len
[1] = 1+3+4+strlen(vendor
)+4;
104 oggstream
->header
[1] = av_mallocz(oggstream
->header_len
[1]);
105 p
= oggstream
->header
[1];
106 bytestream_put_byte(&p
, 0x84); // last metadata block and vorbis comment
107 bytestream_put_be24(&p
, oggstream
->header_len
[1] - 4);
108 bytestream_put_le32(&p
, strlen(vendor
));
109 bytestream_put_buffer(&p
, vendor
, strlen(vendor
));
110 bytestream_put_le32(&p
, 0); // user comment list length
114 static int ogg_write_header(AVFormatContext
*s
)
116 OGGStreamContext
*oggstream
;
118 for (i
= 0; i
< s
->nb_streams
; i
++) {
119 AVStream
*st
= s
->streams
[i
];
120 if (st
->codec
->codec_type
== CODEC_TYPE_AUDIO
)
121 av_set_pts_info(st
, 64, 1, st
->codec
->sample_rate
);
122 else if (st
->codec
->codec_type
== CODEC_TYPE_VIDEO
)
123 av_set_pts_info(st
, 64, st
->codec
->time_base
.num
, st
->codec
->time_base
.den
);
124 if (st
->codec
->codec_id
!= CODEC_ID_VORBIS
&&
125 st
->codec
->codec_id
!= CODEC_ID_THEORA
&&
126 st
->codec
->codec_id
!= CODEC_ID_FLAC
) {
127 av_log(s
, AV_LOG_ERROR
, "Unsupported codec id in stream %d\n", i
);
131 if (!st
->codec
->extradata
|| !st
->codec
->extradata_size
) {
132 av_log(s
, AV_LOG_ERROR
, "No extradata present\n");
135 oggstream
= av_mallocz(sizeof(*oggstream
));
136 st
->priv_data
= oggstream
;
137 if (st
->codec
->codec_id
== CODEC_ID_FLAC
) {
138 if (ogg_build_flac_headers(st
->codec
->extradata
, st
->codec
->extradata_size
,
139 oggstream
, st
->codec
->flags
& CODEC_FLAG_BITEXACT
) < 0) {
140 av_log(s
, AV_LOG_ERROR
, "Extradata corrupted\n");
141 av_freep(&st
->priv_data
);
144 if (ff_split_xiph_headers(st
->codec
->extradata
, st
->codec
->extradata_size
,
145 st
->codec
->codec_id
== CODEC_ID_VORBIS
? 30 : 42,
146 oggstream
->header
, oggstream
->header_len
) < 0) {
147 av_log(s
, AV_LOG_ERROR
, "Extradata corrupted\n");
148 av_freep(&st
->priv_data
);
151 if (st
->codec
->codec_id
== CODEC_ID_THEORA
) {
152 /** KFGSHIFT is the width of the less significant section of the granule position
153 The less significant section is the frame count since the last keyframe */
154 oggstream
->kfgshift
= ((oggstream
->header
[0][40]&3)<<3)|(oggstream
->header
[0][41]>>5);
155 oggstream
->vrev
= oggstream
->header
[0][9];
156 av_log(s
, AV_LOG_DEBUG
, "theora kfgshift %d, vrev %d\n",
157 oggstream
->kfgshift
, oggstream
->vrev
);
161 for (i
= 0; i
< 3; i
++) {
162 for (j
= 0; j
< s
->nb_streams
; j
++) {
163 AVStream
*st
= s
->streams
[j
];
164 OGGStreamContext
*oggstream
= st
->priv_data
;
165 if (oggstream
&& oggstream
->header_len
[i
]) {
166 ogg_write_page(s
, oggstream
->header
[i
], oggstream
->header_len
[i
],
167 0, st
->index
, i
? 0 : 2); // bos
174 static int ogg_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
176 AVStream
*st
= s
->streams
[pkt
->stream_index
];
177 OGGStreamContext
*oggstream
= st
->priv_data
;
178 uint8_t *ptr
= pkt
->data
;
179 int ret
, size
= pkt
->size
;
182 if (st
->codec
->codec_id
== CODEC_ID_THEORA
) {
183 int64_t pts
= oggstream
->vrev
< 1 ? pkt
->pts
: pkt
->pts
+ pkt
->duration
;
185 if (pkt
->flags
& PKT_FLAG_KEY
)
186 oggstream
->last_kf_pts
= pts
;
187 pframe_count
= pts
- oggstream
->last_kf_pts
;
188 // prevent frame count from overflow if key frame flag is not set
189 if (pframe_count
>= (1<<oggstream
->kfgshift
)) {
190 oggstream
->last_kf_pts
+= pframe_count
;
193 granule
= (oggstream
->last_kf_pts
<<oggstream
->kfgshift
) | pframe_count
;
195 granule
= pkt
->pts
+ pkt
->duration
;
196 oggstream
->duration
= granule
;
198 ret
= ogg_write_page(s
, ptr
, size
, granule
, pkt
->stream_index
, ptr
!= pkt
->data
);
199 ptr
+= ret
; size
-= ret
;
200 } while (size
> 0 || ret
== 255*255); // need to output a last nil page
205 int ogg_interleave_per_granule(AVFormatContext
*s
, AVPacket
*out
, AVPacket
*pkt
, int flush
)
207 AVPacketList
*pktl
, **next_point
, *this_pktl
;
208 int stream_count
= 0;
209 int streams
[MAX_STREAMS
] = {0};
213 AVStream
*st
= s
->streams
[pkt
->stream_index
];
214 this_pktl
= av_mallocz(sizeof(AVPacketList
));
215 this_pktl
->pkt
= *pkt
;
216 if (pkt
->destruct
== av_destruct_packet
)
217 pkt
->destruct
= NULL
; // not shared -> must keep original from being freed
219 av_dup_packet(&this_pktl
->pkt
); // shared -> must dup
220 next_point
= &s
->packet_buffer
;
221 while (*next_point
) {
222 AVStream
*st2
= s
->streams
[(*next_point
)->pkt
.stream_index
];
223 AVPacket
*next_pkt
= &(*next_point
)->pkt
;
224 int64_t cur_granule
, next_granule
;
225 next_granule
= av_rescale_q(next_pkt
->pts
+ next_pkt
->duration
,
226 st2
->time_base
, AV_TIME_BASE_Q
);
227 cur_granule
= av_rescale_q(pkt
->pts
+ pkt
->duration
,
228 st
->time_base
, AV_TIME_BASE_Q
);
229 if (next_granule
> cur_granule
)
231 next_point
= &(*next_point
)->next
;
233 this_pktl
->next
= *next_point
;
234 *next_point
= this_pktl
;
237 pktl
= s
->packet_buffer
;
239 if (streams
[pktl
->pkt
.stream_index
] == 0)
241 streams
[pktl
->pkt
.stream_index
]++;
242 // need to buffer at least one packet to set eos flag
243 if (streams
[pktl
->pkt
.stream_index
] == 2)
248 if ((s
->nb_streams
== stream_count
&& interleaved
== stream_count
) ||
249 (flush
&& stream_count
)) {
250 pktl
= s
->packet_buffer
;
252 s
->packet_buffer
= pktl
->next
;
253 if (flush
&& streams
[out
->stream_index
] == 1) {
254 OGGStreamContext
*ogg
= s
->streams
[out
->stream_index
]->priv_data
;
265 static int ogg_write_trailer(AVFormatContext
*s
)
268 for (i
= 0; i
< s
->nb_streams
; i
++) {
269 AVStream
*st
= s
->streams
[i
];
270 OGGStreamContext
*oggstream
= st
->priv_data
;
271 if (st
->codec
->codec_id
== CODEC_ID_FLAC
) {
272 av_free(oggstream
->header
[0]);
273 av_free(oggstream
->header
[1]);
275 av_freep(&st
->priv_data
);
280 AVOutputFormat ogg_muxer
= {
291 .interleave_packet
= ogg_interleave_per_granule
,