ffmpeg / libavformat / asfenc.c @ 6e89b612
History | View | Annotate | Download (29.5 KB)
1 |
/*
|
---|---|
2 |
* ASF muxer
|
3 |
* Copyright (c) 2000, 2001 Fabrice Bellard
|
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 |
#include "avformat.h" |
22 |
#include "metadata.h" |
23 |
#include "riff.h" |
24 |
#include "asf.h" |
25 |
|
26 |
#undef NDEBUG
|
27 |
#include <assert.h> |
28 |
|
29 |
|
30 |
#define ASF_INDEXED_INTERVAL 10000000 |
31 |
#define ASF_INDEX_BLOCK 600 |
32 |
|
33 |
#define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2 |
34 |
#define ASF_PACKET_ERROR_CORRECTION_FLAGS (\
|
35 |
ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT | \ |
36 |
ASF_PACKET_ERROR_CORRECTION_DATA_SIZE\ |
37 |
) |
38 |
|
39 |
#if (ASF_PACKET_ERROR_CORRECTION_FLAGS != 0) |
40 |
# define ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE 1 |
41 |
#else
|
42 |
# define ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE 0 |
43 |
#endif
|
44 |
|
45 |
#define ASF_PPI_PROPERTY_FLAGS (\
|
46 |
ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_BYTE | \ |
47 |
ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_DWORD | \ |
48 |
ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_BYTE | \ |
49 |
ASF_PL_FLAG_STREAM_NUMBER_LENGTH_FIELD_IS_BYTE \ |
50 |
) |
51 |
|
52 |
#define ASF_PPI_LENGTH_TYPE_FLAGS 0 |
53 |
|
54 |
#define ASF_PAYLOAD_FLAGS ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_WORD
|
55 |
|
56 |
#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
|
57 |
# define ASF_PPI_SEQUENCE_FIELD_SIZE 1 |
58 |
#endif
|
59 |
#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
|
60 |
# define ASF_PPI_SEQUENCE_FIELD_SIZE 2 |
61 |
#endif
|
62 |
#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
|
63 |
# define ASF_PPI_SEQUENCE_FIELD_SIZE 4 |
64 |
#endif
|
65 |
#ifndef ASF_PPI_SEQUENCE_FIELD_SIZE
|
66 |
# define ASF_PPI_SEQUENCE_FIELD_SIZE 0 |
67 |
#endif
|
68 |
|
69 |
|
70 |
#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
|
71 |
# define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 1 |
72 |
#endif
|
73 |
#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
|
74 |
# define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 2 |
75 |
#endif
|
76 |
#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
|
77 |
# define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 4 |
78 |
#endif
|
79 |
#ifndef ASF_PPI_PACKET_LENGTH_FIELD_SIZE
|
80 |
# define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 0 |
81 |
#endif
|
82 |
|
83 |
#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
|
84 |
# define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 1 |
85 |
#endif
|
86 |
#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
|
87 |
# define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 2 |
88 |
#endif
|
89 |
#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
|
90 |
# define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 4 |
91 |
#endif
|
92 |
#ifndef ASF_PPI_PADDING_LENGTH_FIELD_SIZE
|
93 |
# define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 0 |
94 |
#endif
|
95 |
|
96 |
#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
|
97 |
# define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 1 |
98 |
#endif
|
99 |
#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
|
100 |
# define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 2 |
101 |
#endif
|
102 |
#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
|
103 |
# define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 4 |
104 |
#endif
|
105 |
#ifndef ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE
|
106 |
# define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 0 |
107 |
#endif
|
108 |
|
109 |
#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
|
110 |
# define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 1 |
111 |
#endif
|
112 |
#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
|
113 |
# define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 2 |
114 |
#endif
|
115 |
#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
|
116 |
# define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 4 |
117 |
#endif
|
118 |
#ifndef ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE
|
119 |
# define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 0 |
120 |
#endif
|
121 |
|
122 |
#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
|
123 |
# define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 1 |
124 |
#endif
|
125 |
#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
|
126 |
# define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 2 |
127 |
#endif
|
128 |
#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
|
129 |
# define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 4 |
130 |
#endif
|
131 |
#ifndef ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE
|
132 |
# define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 0 |
133 |
#endif
|
134 |
|
135 |
#if (ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_BYTE == (ASF_PAYLOAD_FLAGS & ASF_PL_MASK_PAYLOAD_LENGTH_FIELD_SIZE))
|
136 |
# define ASF_PAYLOAD_LENGTH_FIELD_SIZE 1 |
137 |
#endif
|
138 |
#if (ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_WORD == (ASF_PAYLOAD_FLAGS & ASF_PL_MASK_PAYLOAD_LENGTH_FIELD_SIZE))
|
139 |
# define ASF_PAYLOAD_LENGTH_FIELD_SIZE 2 |
140 |
#endif
|
141 |
#ifndef ASF_PAYLOAD_LENGTH_FIELD_SIZE
|
142 |
# define ASF_PAYLOAD_LENGTH_FIELD_SIZE 0 |
143 |
#endif
|
144 |
|
145 |
#define PACKET_HEADER_MIN_SIZE (\
|
146 |
ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE + \ |
147 |
ASF_PACKET_ERROR_CORRECTION_DATA_SIZE + \ |
148 |
1 + /*Length Type Flags*/ \ |
149 |
1 + /*Property Flags*/ \ |
150 |
ASF_PPI_PACKET_LENGTH_FIELD_SIZE + \ |
151 |
ASF_PPI_SEQUENCE_FIELD_SIZE + \ |
152 |
ASF_PPI_PADDING_LENGTH_FIELD_SIZE + \ |
153 |
4 + /*Send Time Field*/ \ |
154 |
2 /*Duration Field*/ \ |
155 |
) |
156 |
|
157 |
|
158 |
// Replicated Data shall be at least 8 bytes long.
|
159 |
#define ASF_PAYLOAD_REPLICATED_DATA_LENGTH 0x08 |
160 |
|
161 |
#define PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD (\
|
162 |
1 + /*Stream Number*/ \ |
163 |
ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE + \ |
164 |
ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE + \ |
165 |
ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE + \ |
166 |
ASF_PAYLOAD_REPLICATED_DATA_LENGTH \ |
167 |
) |
168 |
|
169 |
#define PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS (\
|
170 |
1 + /*Stream Number*/ \ |
171 |
ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE + \ |
172 |
ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE + \ |
173 |
ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE + \ |
174 |
ASF_PAYLOAD_REPLICATED_DATA_LENGTH + \ |
175 |
ASF_PAYLOAD_LENGTH_FIELD_SIZE \ |
176 |
) |
177 |
|
178 |
#define SINGLE_PAYLOAD_DATA_LENGTH (\
|
179 |
PACKET_SIZE - \ |
180 |
PACKET_HEADER_MIN_SIZE - \ |
181 |
PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD \ |
182 |
) |
183 |
|
184 |
#define MULTI_PAYLOAD_CONSTANT (\
|
185 |
PACKET_SIZE - \ |
186 |
PACKET_HEADER_MIN_SIZE - \ |
187 |
1 - /*Payload Flags*/ \ |
188 |
2*PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS \
|
189 |
) |
190 |
|
191 |
static const AVCodecTag codec_asf_bmp_tags[] = { |
192 |
{ CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') }, |
193 |
{ CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') }, |
194 |
{ CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, |
195 |
{ CODEC_ID_NONE, 0 },
|
196 |
}; |
197 |
|
198 |
#define PREROLL_TIME 3100 |
199 |
|
200 |
static void put_guid(ByteIOContext *s, const ff_asf_guid *g) |
201 |
{ |
202 |
assert(sizeof(*g) == 16); |
203 |
put_buffer(s, *g, sizeof(*g));
|
204 |
} |
205 |
|
206 |
static void put_str16(ByteIOContext *s, const char *tag) |
207 |
{ |
208 |
int len;
|
209 |
uint8_t *pb; |
210 |
ByteIOContext *dyn_buf; |
211 |
if (url_open_dyn_buf(&dyn_buf) < 0) |
212 |
return;
|
213 |
|
214 |
avio_put_str16le(dyn_buf, tag); |
215 |
len = url_close_dyn_buf(dyn_buf, &pb); |
216 |
put_le16(s, len); |
217 |
put_buffer(s, pb, len); |
218 |
av_freep(&pb); |
219 |
} |
220 |
|
221 |
static int64_t put_header(ByteIOContext *pb, const ff_asf_guid *g) |
222 |
{ |
223 |
int64_t pos; |
224 |
|
225 |
pos = url_ftell(pb); |
226 |
put_guid(pb, g); |
227 |
put_le64(pb, 24);
|
228 |
return pos;
|
229 |
} |
230 |
|
231 |
/* update header size */
|
232 |
static void end_header(ByteIOContext *pb, int64_t pos) |
233 |
{ |
234 |
int64_t pos1; |
235 |
|
236 |
pos1 = url_ftell(pb); |
237 |
url_fseek(pb, pos + 16, SEEK_SET);
|
238 |
put_le64(pb, pos1 - pos); |
239 |
url_fseek(pb, pos1, SEEK_SET); |
240 |
} |
241 |
|
242 |
/* write an asf chunk (only used in streaming case) */
|
243 |
static void put_chunk(AVFormatContext *s, int type, int payload_length, int flags) |
244 |
{ |
245 |
ASFContext *asf = s->priv_data; |
246 |
ByteIOContext *pb = s->pb; |
247 |
int length;
|
248 |
|
249 |
length = payload_length + 8;
|
250 |
put_le16(pb, type); |
251 |
put_le16(pb, length); //size
|
252 |
put_le32(pb, asf->seqno);//sequence number
|
253 |
put_le16(pb, flags); /* unknown bytes */
|
254 |
put_le16(pb, length); //size_confirm
|
255 |
asf->seqno++; |
256 |
} |
257 |
|
258 |
/* convert from unix to windows time */
|
259 |
static int64_t unix_to_file_time(int ti) |
260 |
{ |
261 |
int64_t t; |
262 |
|
263 |
t = ti * INT64_C(10000000);
|
264 |
t += INT64_C(116444736000000000);
|
265 |
return t;
|
266 |
} |
267 |
|
268 |
/* write the header (used two times if non streamed) */
|
269 |
static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) |
270 |
{ |
271 |
ASFContext *asf = s->priv_data; |
272 |
ByteIOContext *pb = s->pb; |
273 |
AVMetadataTag *tags[5];
|
274 |
int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
|
275 |
int has_title;
|
276 |
int metadata_count;
|
277 |
AVCodecContext *enc; |
278 |
int64_t header_offset, cur_pos, hpos; |
279 |
int bit_rate;
|
280 |
int64_t duration; |
281 |
|
282 |
ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
|
283 |
|
284 |
tags[0] = av_metadata_get(s->metadata, "title" , NULL, 0); |
285 |
tags[1] = av_metadata_get(s->metadata, "author" , NULL, 0); |
286 |
tags[2] = av_metadata_get(s->metadata, "copyright", NULL, 0); |
287 |
tags[3] = av_metadata_get(s->metadata, "comment" , NULL, 0); |
288 |
tags[4] = av_metadata_get(s->metadata, "rating" , NULL, 0); |
289 |
|
290 |
duration = asf->duration + PREROLL_TIME * 10000;
|
291 |
has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4]; |
292 |
metadata_count = s->metadata ? s->metadata->count : 0;
|
293 |
|
294 |
bit_rate = 0;
|
295 |
for(n=0;n<s->nb_streams;n++) { |
296 |
enc = s->streams[n]->codec; |
297 |
|
298 |
av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ |
299 |
|
300 |
bit_rate += enc->bit_rate; |
301 |
} |
302 |
|
303 |
if (asf->is_streamed) {
|
304 |
put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ |
305 |
} |
306 |
|
307 |
put_guid(pb, &ff_asf_header); |
308 |
put_le64(pb, -1); /* header length, will be patched after */ |
309 |
put_le32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */ |
310 |
put_byte(pb, 1); /* ??? */ |
311 |
put_byte(pb, 2); /* ??? */ |
312 |
|
313 |
/* file header */
|
314 |
header_offset = url_ftell(pb); |
315 |
hpos = put_header(pb, &ff_asf_file_header); |
316 |
put_guid(pb, &ff_asf_my_guid); |
317 |
put_le64(pb, file_size); |
318 |
file_time = 0;
|
319 |
put_le64(pb, unix_to_file_time(file_time)); |
320 |
put_le64(pb, asf->nb_packets); /* number of packets */
|
321 |
put_le64(pb, duration); /* end time stamp (in 100ns units) */
|
322 |
put_le64(pb, asf->duration); /* duration (in 100ns units) */
|
323 |
put_le64(pb, PREROLL_TIME); /* start time stamp */
|
324 |
put_le32(pb, (asf->is_streamed || url_is_streamed(pb)) ? 3 : 2); /* ??? */ |
325 |
put_le32(pb, s->packet_size); /* packet size */
|
326 |
put_le32(pb, s->packet_size); /* packet size */
|
327 |
put_le32(pb, bit_rate); /* Nominal data rate in bps */
|
328 |
end_header(pb, hpos); |
329 |
|
330 |
/* unknown headers */
|
331 |
hpos = put_header(pb, &ff_asf_head1_guid); |
332 |
put_guid(pb, &ff_asf_head2_guid); |
333 |
put_le32(pb, 6);
|
334 |
put_le16(pb, 0);
|
335 |
end_header(pb, hpos); |
336 |
|
337 |
/* title and other infos */
|
338 |
if (has_title) {
|
339 |
int len;
|
340 |
uint8_t *buf; |
341 |
ByteIOContext *dyn_buf; |
342 |
|
343 |
if (url_open_dyn_buf(&dyn_buf) < 0) |
344 |
return AVERROR(ENOMEM);
|
345 |
|
346 |
hpos = put_header(pb, &ff_asf_comment_header); |
347 |
|
348 |
for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) { |
349 |
len = tags[n] ? avio_put_str16le(dyn_buf, tags[n]->value) : 0;
|
350 |
put_le16(pb, len); |
351 |
} |
352 |
len = url_close_dyn_buf(dyn_buf, &buf); |
353 |
put_buffer(pb, buf, len); |
354 |
av_freep(&buf); |
355 |
end_header(pb, hpos); |
356 |
} |
357 |
if (metadata_count) {
|
358 |
AVMetadataTag *tag = NULL;
|
359 |
hpos = put_header(pb, &ff_asf_extended_content_header); |
360 |
put_le16(pb, metadata_count); |
361 |
while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) { |
362 |
put_str16(pb, tag->key); |
363 |
put_le16(pb, 0);
|
364 |
put_str16(pb, tag->value); |
365 |
} |
366 |
end_header(pb, hpos); |
367 |
} |
368 |
|
369 |
/* stream headers */
|
370 |
for(n=0;n<s->nb_streams;n++) { |
371 |
int64_t es_pos; |
372 |
// ASFStream *stream = &asf->streams[n];
|
373 |
|
374 |
enc = s->streams[n]->codec; |
375 |
asf->streams[n].num = n + 1;
|
376 |
asf->streams[n].seq = 0;
|
377 |
|
378 |
|
379 |
switch(enc->codec_type) {
|
380 |
case AVMEDIA_TYPE_AUDIO:
|
381 |
wav_extra_size = 0;
|
382 |
extra_size = 18 + wav_extra_size;
|
383 |
extra_size2 = 8;
|
384 |
break;
|
385 |
default:
|
386 |
case AVMEDIA_TYPE_VIDEO:
|
387 |
wav_extra_size = enc->extradata_size; |
388 |
extra_size = 0x33 + wav_extra_size;
|
389 |
extra_size2 = 0;
|
390 |
break;
|
391 |
} |
392 |
|
393 |
hpos = put_header(pb, &ff_asf_stream_header); |
394 |
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
395 |
put_guid(pb, &ff_asf_audio_stream); |
396 |
put_guid(pb, &ff_asf_audio_conceal_spread); |
397 |
} else {
|
398 |
put_guid(pb, &ff_asf_video_stream); |
399 |
put_guid(pb, &ff_asf_video_conceal_none); |
400 |
} |
401 |
put_le64(pb, 0); /* ??? */ |
402 |
es_pos = url_ftell(pb); |
403 |
put_le32(pb, extra_size); /* wav header len */
|
404 |
put_le32(pb, extra_size2); /* additional data len */
|
405 |
put_le16(pb, n + 1); /* stream number */ |
406 |
put_le32(pb, 0); /* ??? */ |
407 |
|
408 |
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
409 |
/* WAVEFORMATEX header */
|
410 |
int wavsize = ff_put_wav_header(pb, enc);
|
411 |
if ((enc->codec_id != CODEC_ID_MP3) && (enc->codec_id != CODEC_ID_MP2) && (enc->codec_id != CODEC_ID_ADPCM_IMA_WAV) && (enc->extradata_size==0)) { |
412 |
wavsize += 2;
|
413 |
put_le16(pb, 0);
|
414 |
} |
415 |
|
416 |
if (wavsize < 0) |
417 |
return -1; |
418 |
if (wavsize != extra_size) {
|
419 |
cur_pos = url_ftell(pb); |
420 |
url_fseek(pb, es_pos, SEEK_SET); |
421 |
put_le32(pb, wavsize); /* wav header len */
|
422 |
url_fseek(pb, cur_pos, SEEK_SET); |
423 |
} |
424 |
/* ERROR Correction */
|
425 |
put_byte(pb, 0x01);
|
426 |
if(enc->codec_id == CODEC_ID_ADPCM_G726 || !enc->block_align){
|
427 |
put_le16(pb, 0x0190);
|
428 |
put_le16(pb, 0x0190);
|
429 |
}else{
|
430 |
put_le16(pb, enc->block_align); |
431 |
put_le16(pb, enc->block_align); |
432 |
} |
433 |
put_le16(pb, 0x01);
|
434 |
put_byte(pb, 0x00);
|
435 |
} else {
|
436 |
put_le32(pb, enc->width); |
437 |
put_le32(pb, enc->height); |
438 |
put_byte(pb, 2); /* ??? */ |
439 |
put_le16(pb, 40 + enc->extradata_size); /* size */ |
440 |
|
441 |
/* BITMAPINFOHEADER header */
|
442 |
ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1);
|
443 |
} |
444 |
end_header(pb, hpos); |
445 |
} |
446 |
|
447 |
/* media comments */
|
448 |
|
449 |
hpos = put_header(pb, &ff_asf_codec_comment_header); |
450 |
put_guid(pb, &ff_asf_codec_comment1_header); |
451 |
put_le32(pb, s->nb_streams); |
452 |
for(n=0;n<s->nb_streams;n++) { |
453 |
AVCodec *p; |
454 |
const char *desc; |
455 |
int len;
|
456 |
uint8_t *buf; |
457 |
ByteIOContext *dyn_buf; |
458 |
|
459 |
enc = s->streams[n]->codec; |
460 |
p = avcodec_find_encoder(enc->codec_id); |
461 |
|
462 |
if(enc->codec_type == AVMEDIA_TYPE_AUDIO)
|
463 |
put_le16(pb, 2);
|
464 |
else if(enc->codec_type == AVMEDIA_TYPE_VIDEO) |
465 |
put_le16(pb, 1);
|
466 |
else
|
467 |
put_le16(pb, -1);
|
468 |
|
469 |
if(enc->codec_id == CODEC_ID_WMAV2)
|
470 |
desc = "Windows Media Audio V8";
|
471 |
else
|
472 |
desc = p ? p->name : enc->codec_name; |
473 |
|
474 |
if ( url_open_dyn_buf(&dyn_buf) < 0) |
475 |
return AVERROR(ENOMEM);
|
476 |
|
477 |
avio_put_str16le(dyn_buf, desc); |
478 |
len = url_close_dyn_buf(dyn_buf, &buf); |
479 |
put_le16(pb, len / 2); // "number of characters" = length in bytes / 2 |
480 |
|
481 |
put_buffer(pb, buf, len); |
482 |
av_freep(&buf); |
483 |
|
484 |
put_le16(pb, 0); /* no parameters */ |
485 |
|
486 |
|
487 |
/* id */
|
488 |
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
489 |
put_le16(pb, 2);
|
490 |
put_le16(pb, enc->codec_tag); |
491 |
} else {
|
492 |
put_le16(pb, 4);
|
493 |
put_le32(pb, enc->codec_tag); |
494 |
} |
495 |
if(!enc->codec_tag)
|
496 |
return -1; |
497 |
} |
498 |
end_header(pb, hpos); |
499 |
|
500 |
/* patch the header size fields */
|
501 |
|
502 |
cur_pos = url_ftell(pb); |
503 |
header_size = cur_pos - header_offset; |
504 |
if (asf->is_streamed) {
|
505 |
header_size += 8 + 30 + 50; |
506 |
|
507 |
url_fseek(pb, header_offset - 10 - 30, SEEK_SET); |
508 |
put_le16(pb, header_size); |
509 |
url_fseek(pb, header_offset - 2 - 30, SEEK_SET); |
510 |
put_le16(pb, header_size); |
511 |
|
512 |
header_size -= 8 + 30 + 50; |
513 |
} |
514 |
header_size += 24 + 6; |
515 |
url_fseek(pb, header_offset - 14, SEEK_SET);
|
516 |
put_le64(pb, header_size); |
517 |
url_fseek(pb, cur_pos, SEEK_SET); |
518 |
|
519 |
/* movie chunk, followed by packets of packet_size */
|
520 |
asf->data_offset = cur_pos; |
521 |
put_guid(pb, &ff_asf_data_header); |
522 |
put_le64(pb, data_chunk_size); |
523 |
put_guid(pb, &ff_asf_my_guid); |
524 |
put_le64(pb, asf->nb_packets); /* nb packets */
|
525 |
put_byte(pb, 1); /* ??? */ |
526 |
put_byte(pb, 1); /* ??? */ |
527 |
return 0; |
528 |
} |
529 |
|
530 |
static int asf_write_header(AVFormatContext *s) |
531 |
{ |
532 |
ASFContext *asf = s->priv_data; |
533 |
|
534 |
s->packet_size = PACKET_SIZE; |
535 |
asf->nb_packets = 0;
|
536 |
|
537 |
asf->last_indexed_pts = 0;
|
538 |
asf->index_ptr = av_malloc( sizeof(ASFIndex) * ASF_INDEX_BLOCK );
|
539 |
asf->nb_index_memory_alloc = ASF_INDEX_BLOCK; |
540 |
asf->nb_index_count = 0;
|
541 |
asf->maximum_packet = 0;
|
542 |
|
543 |
/* the data-chunk-size has to be 50, which is data_size - asf->data_offset
|
544 |
* at the moment this function is done. It is needed to use asf as
|
545 |
* streamable format. */
|
546 |
if (asf_write_header1(s, 0, 50) < 0) { |
547 |
//av_free(asf);
|
548 |
return -1; |
549 |
} |
550 |
|
551 |
put_flush_packet(s->pb); |
552 |
|
553 |
asf->packet_nb_payloads = 0;
|
554 |
asf->packet_timestamp_start = -1;
|
555 |
asf->packet_timestamp_end = -1;
|
556 |
init_put_byte(&asf->pb, asf->packet_buf, s->packet_size, 1,
|
557 |
NULL, NULL, NULL, NULL); |
558 |
|
559 |
return 0; |
560 |
} |
561 |
|
562 |
static int asf_write_stream_header(AVFormatContext *s) |
563 |
{ |
564 |
ASFContext *asf = s->priv_data; |
565 |
|
566 |
asf->is_streamed = 1;
|
567 |
|
568 |
return asf_write_header(s);
|
569 |
} |
570 |
|
571 |
static int put_payload_parsing_info( |
572 |
AVFormatContext *s, |
573 |
unsigned int sendtime, |
574 |
unsigned int duration, |
575 |
int nb_payloads,
|
576 |
int padsize
|
577 |
) |
578 |
{ |
579 |
ASFContext *asf = s->priv_data; |
580 |
ByteIOContext *pb = s->pb; |
581 |
int ppi_size, i;
|
582 |
int64_t start= url_ftell(pb); |
583 |
|
584 |
int iLengthTypeFlags = ASF_PPI_LENGTH_TYPE_FLAGS;
|
585 |
|
586 |
padsize -= PACKET_HEADER_MIN_SIZE; |
587 |
if(asf->multi_payloads_present)
|
588 |
padsize--; |
589 |
assert(padsize>=0);
|
590 |
|
591 |
put_byte(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS); |
592 |
for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++){ |
593 |
put_byte(pb, 0x0);
|
594 |
} |
595 |
|
596 |
if (asf->multi_payloads_present)
|
597 |
iLengthTypeFlags |= ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT; |
598 |
|
599 |
if (padsize > 0) { |
600 |
if (padsize < 256) |
601 |
iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE; |
602 |
else
|
603 |
iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD; |
604 |
} |
605 |
put_byte(pb, iLengthTypeFlags); |
606 |
|
607 |
put_byte(pb, ASF_PPI_PROPERTY_FLAGS); |
608 |
|
609 |
if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD)
|
610 |
put_le16(pb, padsize - 2);
|
611 |
if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE)
|
612 |
put_byte(pb, padsize - 1);
|
613 |
|
614 |
put_le32(pb, sendtime); |
615 |
put_le16(pb, duration); |
616 |
if (asf->multi_payloads_present)
|
617 |
put_byte(pb, nb_payloads | ASF_PAYLOAD_FLAGS); |
618 |
|
619 |
ppi_size = url_ftell(pb) - start; |
620 |
|
621 |
return ppi_size;
|
622 |
} |
623 |
|
624 |
static void flush_packet(AVFormatContext *s) |
625 |
{ |
626 |
ASFContext *asf = s->priv_data; |
627 |
int packet_hdr_size, packet_filled_size;
|
628 |
|
629 |
assert(asf->packet_timestamp_end >= asf->packet_timestamp_start); |
630 |
|
631 |
if (asf->is_streamed) {
|
632 |
put_chunk(s, 0x4424, s->packet_size, 0); |
633 |
} |
634 |
|
635 |
packet_hdr_size = put_payload_parsing_info( |
636 |
s, |
637 |
asf->packet_timestamp_start, |
638 |
asf->packet_timestamp_end - asf->packet_timestamp_start, |
639 |
asf->packet_nb_payloads, |
640 |
asf->packet_size_left |
641 |
); |
642 |
|
643 |
packet_filled_size = PACKET_SIZE - asf->packet_size_left; |
644 |
assert(packet_hdr_size <= asf->packet_size_left); |
645 |
memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left);
|
646 |
|
647 |
put_buffer(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size); |
648 |
|
649 |
put_flush_packet(s->pb); |
650 |
asf->nb_packets++; |
651 |
asf->packet_nb_payloads = 0;
|
652 |
asf->packet_timestamp_start = -1;
|
653 |
asf->packet_timestamp_end = -1;
|
654 |
init_put_byte(&asf->pb, asf->packet_buf, s->packet_size, 1,
|
655 |
NULL, NULL, NULL, NULL); |
656 |
} |
657 |
|
658 |
static void put_payload_header( |
659 |
AVFormatContext *s, |
660 |
ASFStream *stream, |
661 |
int presentation_time,
|
662 |
int m_obj_size,
|
663 |
int m_obj_offset,
|
664 |
int payload_len,
|
665 |
int flags
|
666 |
) |
667 |
{ |
668 |
ASFContext *asf = s->priv_data; |
669 |
ByteIOContext *pb = &asf->pb; |
670 |
int val;
|
671 |
|
672 |
val = stream->num; |
673 |
if (flags & AV_PKT_FLAG_KEY)
|
674 |
val |= ASF_PL_FLAG_KEY_FRAME; |
675 |
put_byte(pb, val); |
676 |
|
677 |
put_byte(pb, stream->seq); //Media object number
|
678 |
put_le32(pb, m_obj_offset); //Offset Into Media Object
|
679 |
|
680 |
// Replicated Data shall be at least 8 bytes long.
|
681 |
// The first 4 bytes of data shall contain the
|
682 |
// Size of the Media Object that the payload belongs to.
|
683 |
// The next 4 bytes of data shall contain the
|
684 |
// Presentation Time for the media object that the payload belongs to.
|
685 |
put_byte(pb, ASF_PAYLOAD_REPLICATED_DATA_LENGTH); |
686 |
|
687 |
put_le32(pb, m_obj_size); //Replicated Data - Media Object Size
|
688 |
put_le32(pb, presentation_time);//Replicated Data - Presentation Time
|
689 |
|
690 |
if (asf->multi_payloads_present){
|
691 |
put_le16(pb, payload_len); //payload length
|
692 |
} |
693 |
} |
694 |
|
695 |
static void put_frame( |
696 |
AVFormatContext *s, |
697 |
ASFStream *stream, |
698 |
AVStream *avst, |
699 |
int timestamp,
|
700 |
const uint8_t *buf,
|
701 |
int m_obj_size,
|
702 |
int flags
|
703 |
) |
704 |
{ |
705 |
ASFContext *asf = s->priv_data; |
706 |
int m_obj_offset, payload_len, frag_len1;
|
707 |
|
708 |
m_obj_offset = 0;
|
709 |
while (m_obj_offset < m_obj_size) {
|
710 |
payload_len = m_obj_size - m_obj_offset; |
711 |
if (asf->packet_timestamp_start == -1) { |
712 |
asf->multi_payloads_present = (payload_len < MULTI_PAYLOAD_CONSTANT); |
713 |
|
714 |
asf->packet_size_left = PACKET_SIZE; |
715 |
if (asf->multi_payloads_present){
|
716 |
frag_len1 = MULTI_PAYLOAD_CONSTANT - 1;
|
717 |
} |
718 |
else {
|
719 |
frag_len1 = SINGLE_PAYLOAD_DATA_LENGTH; |
720 |
} |
721 |
asf->packet_timestamp_start = timestamp; |
722 |
} |
723 |
else {
|
724 |
// multi payloads
|
725 |
frag_len1 = asf->packet_size_left - PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS - PACKET_HEADER_MIN_SIZE - 1;
|
726 |
|
727 |
if(frag_len1 < payload_len && avst->codec->codec_type == AVMEDIA_TYPE_AUDIO){
|
728 |
flush_packet(s); |
729 |
continue;
|
730 |
} |
731 |
} |
732 |
if (frag_len1 > 0) { |
733 |
if (payload_len > frag_len1)
|
734 |
payload_len = frag_len1; |
735 |
else if (payload_len == (frag_len1 - 1)) |
736 |
payload_len = frag_len1 - 2; //additional byte need to put padding length |
737 |
|
738 |
put_payload_header(s, stream, timestamp+PREROLL_TIME, m_obj_size, m_obj_offset, payload_len, flags); |
739 |
put_buffer(&asf->pb, buf, payload_len); |
740 |
|
741 |
if (asf->multi_payloads_present)
|
742 |
asf->packet_size_left -= (payload_len + PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS); |
743 |
else
|
744 |
asf->packet_size_left -= (payload_len + PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD); |
745 |
asf->packet_timestamp_end = timestamp; |
746 |
|
747 |
asf->packet_nb_payloads++; |
748 |
} else {
|
749 |
payload_len = 0;
|
750 |
} |
751 |
m_obj_offset += payload_len; |
752 |
buf += payload_len; |
753 |
|
754 |
if (!asf->multi_payloads_present)
|
755 |
flush_packet(s); |
756 |
else if (asf->packet_size_left <= (PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS + PACKET_HEADER_MIN_SIZE + 1)) |
757 |
flush_packet(s); |
758 |
} |
759 |
stream->seq++; |
760 |
} |
761 |
|
762 |
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt) |
763 |
{ |
764 |
ASFContext *asf = s->priv_data; |
765 |
ASFStream *stream; |
766 |
int64_t duration; |
767 |
AVCodecContext *codec; |
768 |
int64_t packet_st,pts; |
769 |
int start_sec,i;
|
770 |
int flags= pkt->flags;
|
771 |
|
772 |
codec = s->streams[pkt->stream_index]->codec; |
773 |
stream = &asf->streams[pkt->stream_index]; |
774 |
|
775 |
if(codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
776 |
flags &= ~AV_PKT_FLAG_KEY; |
777 |
|
778 |
pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts; |
779 |
assert(pts != AV_NOPTS_VALUE); |
780 |
duration = pts * 10000;
|
781 |
asf->duration= FFMAX(asf->duration, duration + pkt->duration * 10000);
|
782 |
|
783 |
packet_st = asf->nb_packets; |
784 |
put_frame(s, stream, s->streams[pkt->stream_index], pkt->dts, pkt->data, pkt->size, flags); |
785 |
|
786 |
/* check index */
|
787 |
if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
|
788 |
start_sec = (int)(duration / INT64_C(10000000)); |
789 |
if (start_sec != (int)(asf->last_indexed_pts / INT64_C(10000000))) { |
790 |
for(i=asf->nb_index_count;i<start_sec;i++) {
|
791 |
if (i>=asf->nb_index_memory_alloc) {
|
792 |
asf->nb_index_memory_alloc += ASF_INDEX_BLOCK; |
793 |
asf->index_ptr = (ASFIndex*)av_realloc( asf->index_ptr, sizeof(ASFIndex) * asf->nb_index_memory_alloc );
|
794 |
} |
795 |
// store
|
796 |
asf->index_ptr[i].packet_number = (uint32_t)packet_st; |
797 |
asf->index_ptr[i].packet_count = (uint16_t)(asf->nb_packets-packet_st); |
798 |
asf->maximum_packet = FFMAX(asf->maximum_packet, (uint16_t)(asf->nb_packets-packet_st)); |
799 |
} |
800 |
asf->nb_index_count = start_sec; |
801 |
asf->last_indexed_pts = duration; |
802 |
} |
803 |
} |
804 |
return 0; |
805 |
} |
806 |
|
807 |
//
|
808 |
static int asf_write_index(AVFormatContext *s, ASFIndex *index, uint16_t max, uint32_t count) |
809 |
{ |
810 |
ByteIOContext *pb = s->pb; |
811 |
int i;
|
812 |
|
813 |
put_guid(pb, &ff_asf_simple_index_header); |
814 |
put_le64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2)*count); |
815 |
put_guid(pb, &ff_asf_my_guid); |
816 |
put_le64(pb, ASF_INDEXED_INTERVAL); |
817 |
put_le32(pb, max); |
818 |
put_le32(pb, count); |
819 |
for(i=0; i<count; i++) { |
820 |
put_le32(pb, index[i].packet_number); |
821 |
put_le16(pb, index[i].packet_count); |
822 |
} |
823 |
|
824 |
return 0; |
825 |
} |
826 |
|
827 |
static int asf_write_trailer(AVFormatContext *s) |
828 |
{ |
829 |
ASFContext *asf = s->priv_data; |
830 |
int64_t file_size,data_size; |
831 |
|
832 |
/* flush the current packet */
|
833 |
if (asf->pb.buf_ptr > asf->pb.buffer)
|
834 |
flush_packet(s); |
835 |
|
836 |
/* write index */
|
837 |
data_size = url_ftell(s->pb); |
838 |
if ((!asf->is_streamed) && (asf->nb_index_count != 0)) { |
839 |
asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->nb_index_count); |
840 |
} |
841 |
put_flush_packet(s->pb); |
842 |
|
843 |
if (asf->is_streamed || url_is_streamed(s->pb)) {
|
844 |
put_chunk(s, 0x4524, 0, 0); /* end of stream */ |
845 |
} else {
|
846 |
/* rewrite an updated header */
|
847 |
file_size = url_ftell(s->pb); |
848 |
url_fseek(s->pb, 0, SEEK_SET);
|
849 |
asf_write_header1(s, file_size, data_size - asf->data_offset); |
850 |
} |
851 |
|
852 |
put_flush_packet(s->pb); |
853 |
av_free(asf->index_ptr); |
854 |
return 0; |
855 |
} |
856 |
|
857 |
#if CONFIG_ASF_MUXER
|
858 |
AVOutputFormat asf_muxer = { |
859 |
"asf",
|
860 |
NULL_IF_CONFIG_SMALL("ASF format"),
|
861 |
"video/x-ms-asf",
|
862 |
"asf,wmv,wma",
|
863 |
sizeof(ASFContext),
|
864 |
#if CONFIG_LIBMP3LAME
|
865 |
CODEC_ID_MP3, |
866 |
#else
|
867 |
CODEC_ID_MP2, |
868 |
#endif
|
869 |
CODEC_ID_MSMPEG4V3, |
870 |
asf_write_header, |
871 |
asf_write_packet, |
872 |
asf_write_trailer, |
873 |
.flags = AVFMT_GLOBALHEADER, |
874 |
.codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0}, |
875 |
}; |
876 |
#endif
|
877 |
|
878 |
#if CONFIG_ASF_STREAM_MUXER
|
879 |
AVOutputFormat asf_stream_muxer = { |
880 |
"asf_stream",
|
881 |
NULL_IF_CONFIG_SMALL("ASF format"),
|
882 |
"video/x-ms-asf",
|
883 |
"asf,wmv,wma",
|
884 |
sizeof(ASFContext),
|
885 |
#if CONFIG_LIBMP3LAME
|
886 |
CODEC_ID_MP3, |
887 |
#else
|
888 |
CODEC_ID_MP2, |
889 |
#endif
|
890 |
CODEC_ID_MSMPEG4V3, |
891 |
asf_write_stream_header, |
892 |
asf_write_packet, |
893 |
asf_write_trailer, |
894 |
.flags = AVFMT_GLOBALHEADER, |
895 |
.codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0}, |
896 |
}; |
897 |
#endif //CONFIG_ASF_STREAM_MUXER |