00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023 #include "crc.h"
00024 #include "xiph.h"
00025 #include "bytestream.h"
00026
00027 typedef struct {
00028 int64_t duration;
00029 unsigned page_counter;
00030 uint8_t *header[3];
00031 int header_len[3];
00033 int kfgshift;
00034 int64_t last_kf_pts;
00035 int vrev;
00036 int eos;
00037 } OGGStreamContext;
00038
00039 static void ogg_update_checksum(AVFormatContext *s, offset_t crc_offset)
00040 {
00041 offset_t pos = url_ftell(s->pb);
00042 uint32_t checksum = get_checksum(s->pb);
00043 url_fseek(s->pb, crc_offset, SEEK_SET);
00044 put_be32(s->pb, checksum);
00045 url_fseek(s->pb, pos, SEEK_SET);
00046 }
00047
00048 static int ogg_write_page(AVFormatContext *s, const uint8_t *data, int size,
00049 int64_t granule, int stream_index, int flags)
00050 {
00051 OGGStreamContext *oggstream = s->streams[stream_index]->priv_data;
00052 offset_t crc_offset;
00053 int page_segments, i;
00054
00055 if (size >= 255*255) {
00056 granule = -1;
00057 size = 255*255;
00058 } else if (oggstream->eos)
00059 flags |= 4;
00060
00061 page_segments = FFMIN((size/255)+!!size, 255);
00062
00063 init_checksum(s->pb, ff_crc04C11DB7_update, 0);
00064 put_tag(s->pb, "OggS");
00065 put_byte(s->pb, 0);
00066 put_byte(s->pb, flags);
00067 put_le64(s->pb, granule);
00068 put_le32(s->pb, stream_index);
00069 put_le32(s->pb, oggstream->page_counter++);
00070 crc_offset = url_ftell(s->pb);
00071 put_le32(s->pb, 0);
00072 put_byte(s->pb, page_segments);
00073 for (i = 0; i < page_segments-1; i++)
00074 put_byte(s->pb, 255);
00075 if (size) {
00076 put_byte(s->pb, size - (page_segments-1)*255);
00077 put_buffer(s->pb, data, size);
00078 }
00079 ogg_update_checksum(s, crc_offset);
00080 put_flush_packet(s->pb);
00081 return size;
00082 }
00083
00084 static int ogg_build_flac_headers(const uint8_t *extradata, int extradata_size,
00085 OGGStreamContext *oggstream, int bitexact)
00086 {
00087 const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
00088 uint8_t *p;
00089 if (extradata_size != 34)
00090 return -1;
00091 oggstream->header_len[0] = 79;
00092 oggstream->header[0] = av_mallocz(79);
00093 p = oggstream->header[0];
00094 bytestream_put_byte(&p, 0x7F);
00095 bytestream_put_buffer(&p, "FLAC", 4);
00096 bytestream_put_byte(&p, 1);
00097 bytestream_put_byte(&p, 0);
00098 bytestream_put_be16(&p, 1);
00099 bytestream_put_buffer(&p, "fLaC", 4);
00100 bytestream_put_byte(&p, 0x00);
00101 bytestream_put_be24(&p, 34);
00102 bytestream_put_buffer(&p, extradata, 34);
00103 oggstream->header_len[1] = 1+3+4+strlen(vendor)+4;
00104 oggstream->header[1] = av_mallocz(oggstream->header_len[1]);
00105 p = oggstream->header[1];
00106 bytestream_put_byte(&p, 0x84);
00107 bytestream_put_be24(&p, oggstream->header_len[1] - 4);
00108 bytestream_put_le32(&p, strlen(vendor));
00109 bytestream_put_buffer(&p, vendor, strlen(vendor));
00110 bytestream_put_le32(&p, 0);
00111 return 0;
00112 }
00113
00114 static int ogg_write_header(AVFormatContext *s)
00115 {
00116 OGGStreamContext *oggstream;
00117 int i, j;
00118 for (i = 0; i < s->nb_streams; i++) {
00119 AVStream *st = s->streams[i];
00120 if (st->codec->codec_type == CODEC_TYPE_AUDIO)
00121 av_set_pts_info(st, 64, 1, st->codec->sample_rate);
00122 else if (st->codec->codec_type == CODEC_TYPE_VIDEO)
00123 av_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
00124 if (st->codec->codec_id != CODEC_ID_VORBIS &&
00125 st->codec->codec_id != CODEC_ID_THEORA &&
00126 st->codec->codec_id != CODEC_ID_FLAC) {
00127 av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i);
00128 return -1;
00129 }
00130
00131 if (!st->codec->extradata || !st->codec->extradata_size) {
00132 av_log(s, AV_LOG_ERROR, "No extradata present\n");
00133 return -1;
00134 }
00135 oggstream = av_mallocz(sizeof(*oggstream));
00136 st->priv_data = oggstream;
00137 if (st->codec->codec_id == CODEC_ID_FLAC) {
00138 if (ogg_build_flac_headers(st->codec->extradata, st->codec->extradata_size,
00139 oggstream, st->codec->flags & CODEC_FLAG_BITEXACT) < 0) {
00140 av_log(s, AV_LOG_ERROR, "Extradata corrupted\n");
00141 av_freep(&st->priv_data);
00142 }
00143 } else {
00144 if (ff_split_xiph_headers(st->codec->extradata, st->codec->extradata_size,
00145 st->codec->codec_id == CODEC_ID_VORBIS ? 30 : 42,
00146 oggstream->header, oggstream->header_len) < 0) {
00147 av_log(s, AV_LOG_ERROR, "Extradata corrupted\n");
00148 av_freep(&st->priv_data);
00149 return -1;
00150 }
00151 if (st->codec->codec_id == CODEC_ID_THEORA) {
00154 oggstream->kfgshift = ((oggstream->header[0][40]&3)<<3)|(oggstream->header[0][41]>>5);
00155 oggstream->vrev = oggstream->header[0][9];
00156 av_log(s, AV_LOG_DEBUG, "theora kfgshift %d, vrev %d\n",
00157 oggstream->kfgshift, oggstream->vrev);
00158 }
00159 }
00160 }
00161 for (i = 0; i < 3; i++) {
00162 for (j = 0; j < s->nb_streams; j++) {
00163 AVStream *st = s->streams[j];
00164 OGGStreamContext *oggstream = st->priv_data;
00165 if (oggstream && oggstream->header_len[i]) {
00166 ogg_write_page(s, oggstream->header[i], oggstream->header_len[i],
00167 0, st->index, i ? 0 : 2);
00168 }
00169 }
00170 }
00171 return 0;
00172 }
00173
00174 static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt)
00175 {
00176 AVStream *st = s->streams[pkt->stream_index];
00177 OGGStreamContext *oggstream = st->priv_data;
00178 uint8_t *ptr = pkt->data;
00179 int ret, size = pkt->size;
00180 int64_t granule;
00181
00182 if (st->codec->codec_id == CODEC_ID_THEORA) {
00183 int64_t pts = oggstream->vrev < 1 ? pkt->pts : pkt->pts + pkt->duration;
00184 int pframe_count;
00185 if (pkt->flags & PKT_FLAG_KEY)
00186 oggstream->last_kf_pts = pts;
00187 pframe_count = pts - oggstream->last_kf_pts;
00188
00189 if (pframe_count >= (1<<oggstream->kfgshift)) {
00190 oggstream->last_kf_pts += pframe_count;
00191 pframe_count = 0;
00192 }
00193 granule = (oggstream->last_kf_pts<<oggstream->kfgshift) | pframe_count;
00194 } else
00195 granule = pkt->pts + pkt->duration;
00196 oggstream->duration = granule;
00197 do {
00198 ret = ogg_write_page(s, ptr, size, granule, pkt->stream_index, ptr != pkt->data);
00199 ptr += ret; size -= ret;
00200 } while (size > 0 || ret == 255*255);
00201
00202 return 0;
00203 }
00204
00205 int ogg_interleave_per_granule(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush)
00206 {
00207 AVPacketList *pktl, **next_point, *this_pktl;
00208 int stream_count = 0;
00209 int streams[MAX_STREAMS] = {0};
00210 int interleaved = 0;
00211
00212 if (pkt) {
00213 AVStream *st = s->streams[pkt->stream_index];
00214 this_pktl = av_mallocz(sizeof(AVPacketList));
00215 this_pktl->pkt = *pkt;
00216 if (pkt->destruct == av_destruct_packet)
00217 pkt->destruct = NULL;
00218 else
00219 av_dup_packet(&this_pktl->pkt);
00220 next_point = &s->packet_buffer;
00221 while (*next_point) {
00222 AVStream *st2 = s->streams[(*next_point)->pkt.stream_index];
00223 AVPacket *next_pkt = &(*next_point)->pkt;
00224 int64_t cur_granule, next_granule;
00225 next_granule = av_rescale_q(next_pkt->pts + next_pkt->duration,
00226 st2->time_base, AV_TIME_BASE_Q);
00227 cur_granule = av_rescale_q(pkt->pts + pkt->duration,
00228 st->time_base, AV_TIME_BASE_Q);
00229 if (next_granule > cur_granule)
00230 break;
00231 next_point= &(*next_point)->next;
00232 }
00233 this_pktl->next= *next_point;
00234 *next_point= this_pktl;
00235 }
00236
00237 pktl = s->packet_buffer;
00238 while (pktl) {
00239 if (streams[pktl->pkt.stream_index] == 0)
00240 stream_count++;
00241 streams[pktl->pkt.stream_index]++;
00242
00243 if (streams[pktl->pkt.stream_index] == 2)
00244 interleaved++;
00245 pktl = pktl->next;
00246 }
00247
00248 if ((s->nb_streams == stream_count && interleaved == stream_count) ||
00249 (flush && stream_count)) {
00250 pktl= s->packet_buffer;
00251 *out= pktl->pkt;
00252 s->packet_buffer = pktl->next;
00253 if (flush && streams[out->stream_index] == 1) {
00254 OGGStreamContext *ogg = s->streams[out->stream_index]->priv_data;
00255 ogg->eos = 1;
00256 }
00257 av_freep(&pktl);
00258 return 1;
00259 } else {
00260 av_init_packet(out);
00261 return 0;
00262 }
00263 }
00264
00265 static int ogg_write_trailer(AVFormatContext *s)
00266 {
00267 int i;
00268 for (i = 0; i < s->nb_streams; i++) {
00269 AVStream *st = s->streams[i];
00270 OGGStreamContext *oggstream = st->priv_data;
00271 if (st->codec->codec_id == CODEC_ID_FLAC) {
00272 av_free(oggstream->header[0]);
00273 av_free(oggstream->header[1]);
00274 }
00275 av_freep(&st->priv_data);
00276 }
00277 return 0;
00278 }
00279
00280 AVOutputFormat ogg_muxer = {
00281 "ogg",
00282 "Ogg format",
00283 "application/ogg",
00284 "ogg",
00285 0,
00286 CODEC_ID_FLAC,
00287 CODEC_ID_THEORA,
00288 ogg_write_header,
00289 ogg_write_packet,
00290 ogg_write_trailer,
00291 .interleave_packet = ogg_interleave_per_granule,
00292 };