Mercurial > libavformat.hg
comparison matroskaenc.c @ 2425:8c51e92edd7d libavformat
Beginning of mkv muxer, only EBML head is written correctly
author | conrad |
---|---|
date | Wed, 05 Sep 2007 00:22:37 +0000 |
parents | |
children | 3d50766df97d |
comparison
equal
deleted
inserted
replaced
2424:491a751cc58c | 2425:8c51e92edd7d |
---|---|
1 /* | |
2 * Matroska file muxer | |
3 * Copyright (c) 2007 David Conrad | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
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. | |
11 * | |
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. | |
16 * | |
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 | |
20 */ | |
21 | |
22 #include "avformat.h" | |
23 #include "riff.h" | |
24 #include "matroska.h" | |
25 | |
26 typedef struct MatroskaMuxContext { | |
27 offset_t segment; | |
28 } MatroskaMuxContext; | |
29 | |
30 static void put_ebml_id(ByteIOContext *pb, unsigned int id) | |
31 { | |
32 if (id >= 0x3fffff) | |
33 put_byte(pb, id >> 24); | |
34 if (id >= 0x7fff) | |
35 put_byte(pb, id >> 16); | |
36 if (id >= 0xff) | |
37 put_byte(pb, id >> 8); | |
38 put_byte(pb, id); | |
39 } | |
40 | |
41 // XXX: test this thoroughly and get rid of minbytes hack (currently needed to | |
42 // use up all of the space reserved in start_ebml_master) | |
43 static void put_ebml_size(ByteIOContext *pb, uint64_t size, int minbytes) | |
44 { | |
45 int bytes = minbytes; | |
46 while (size >> (bytes*8 + 7-bytes) > 0) bytes++; | |
47 | |
48 // sizes larger than this are currently undefined in EBML | |
49 // XXX: error condition? | |
50 if (size > (1ULL<<56)-1) return; | |
51 | |
52 put_byte(pb, (0x80 >> bytes) | (size >> bytes*8)); | |
53 for (bytes -= 1; bytes >= 0; bytes--) | |
54 put_byte(pb, size >> bytes*8); | |
55 } | |
56 | |
57 static void put_ebml_uint(ByteIOContext *pb, unsigned int elementid, uint64_t val) | |
58 { | |
59 int bytes = 1; | |
60 while (val >> bytes*8) bytes++; | |
61 | |
62 put_ebml_id(pb, elementid); | |
63 put_ebml_size(pb, bytes, 0); | |
64 for (bytes -= 1; bytes >= 0; bytes--) | |
65 put_byte(pb, val >> bytes*8); | |
66 } | |
67 | |
68 //static void put_ebml_sint(ByteIOContext *pb, unsigned int elementid, int64_t val) | |
69 | |
70 static void put_ebml_binary(ByteIOContext *pb, unsigned int elementid, | |
71 uint8_t *buf, int size) | |
72 { | |
73 put_ebml_id(pb, elementid); | |
74 put_ebml_size(pb, size, 0); | |
75 put_buffer(pb, buf, size); | |
76 } | |
77 | |
78 // XXX: should we do any special checking for valid strings for these 2 functions? | |
79 static void put_ebml_string(ByteIOContext *pb, unsigned int elementid, char *str) | |
80 { | |
81 put_ebml_binary(pb, elementid, str, strlen(str)); | |
82 } | |
83 | |
84 static void put_ebml_utf8(ByteIOContext *pb, unsigned int elementid, char *str) | |
85 { | |
86 put_ebml_binary(pb, elementid, str, strlen(str)); | |
87 } | |
88 | |
89 static offset_t start_ebml_master(ByteIOContext *pb, unsigned int elementid) | |
90 { | |
91 put_ebml_id(pb, elementid); | |
92 // XXX: this always reserves the maximum needed space to store any size value | |
93 // we should be smarter (additional parameter for expected size?) | |
94 put_ebml_size(pb, (1ULL<<56)-1, 0); // largest unknown size | |
95 return url_ftell(pb); | |
96 } | |
97 | |
98 static void end_ebml_master(ByteIOContext *pb, offset_t start) | |
99 { | |
100 offset_t pos = url_ftell(pb); | |
101 | |
102 url_fseek(pb, start - 8, SEEK_SET); | |
103 put_ebml_size(pb, pos - start, 7); | |
104 url_fseek(pb, pos, SEEK_SET); | |
105 } | |
106 | |
107 | |
108 static int mkv_write_header(AVFormatContext *s) | |
109 { | |
110 MatroskaMuxContext *mkv = s->priv_data; | |
111 ByteIOContext *pb = &s->pb; | |
112 offset_t ebml_header, segment_info, tracks; | |
113 int i; | |
114 | |
115 ebml_header = start_ebml_master(pb, EBML_ID_HEADER); | |
116 put_ebml_uint(pb, EBML_ID_EBMLVERSION, 1); | |
117 put_ebml_uint(pb, EBML_ID_EBMLREADVERSION, 1); | |
118 put_ebml_uint(pb, EBML_ID_EBMLMAXIDLENGTH, 4); | |
119 put_ebml_uint(pb, EBML_ID_EBMLMAXSIZELENGTH, 8); | |
120 put_ebml_string(pb, EBML_ID_DOCTYPE, "matroska"); | |
121 put_ebml_uint(pb, EBML_ID_DOCTYPEVERSION, 1); | |
122 put_ebml_uint(pb, EBML_ID_DOCTYPEREADVERSION, 1); | |
123 end_ebml_master(pb, ebml_header); | |
124 | |
125 mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT); | |
126 | |
127 segment_info = start_ebml_master(pb, MATROSKA_ID_INFO); | |
128 put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000); | |
129 if (strlen(s->title)) | |
130 put_ebml_utf8(pb, MATROSKA_ID_TITLE, s->title); | |
131 if (!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { | |
132 put_ebml_utf8(pb, MATROSKA_ID_MUXINGAPP, LIBAVFORMAT_IDENT); | |
133 // XXX: both are required; something better for writing app? | |
134 put_ebml_utf8(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT); | |
135 } | |
136 // XXX: segment UID and duration | |
137 end_ebml_master(pb, segment_info); | |
138 | |
139 tracks = start_ebml_master(pb, MATROSKA_ID_TRACKS); | |
140 for (i = 0; i < s->nb_streams; i++) { | |
141 AVStream *st = s->streams[i]; | |
142 offset_t track = start_ebml_master(pb, MATROSKA_ID_TRACKENTRY); | |
143 | |
144 end_ebml_master(pb, track); | |
145 } | |
146 end_ebml_master(pb, tracks); | |
147 | |
148 put_be64(pb, 0xdeadbeef); | |
149 return 0; | |
150 } | |
151 | |
152 static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) | |
153 { | |
154 ByteIOContext *pb = &s->pb; | |
155 put_buffer(pb, pkt->data, pkt->size); | |
156 return 0; | |
157 } | |
158 | |
159 static int mkv_write_trailer(AVFormatContext *s) | |
160 { | |
161 MatroskaMuxContext *mkv = s->priv_data; | |
162 ByteIOContext *pb = &s->pb; | |
163 end_ebml_master(pb, mkv->segment); | |
164 return 0; | |
165 } | |
166 | |
167 AVOutputFormat matroska_muxer = { | |
168 "matroska", | |
169 "Matroska File Format", | |
170 "video/x-matroska", | |
171 "mkv", | |
172 sizeof(MatroskaMuxContext), | |
173 CODEC_ID_MP2, | |
174 CODEC_ID_MPEG4, | |
175 mkv_write_header, | |
176 mkv_write_packet, | |
177 mkv_write_trailer, | |
178 .codec_tag = (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0}, | |
179 }; |