Mercurial > libavformat.hg
annotate gxfenc.c @ 1960:c0289552590f libavformat
Change the vhook code to send real timestamps to the filters instead of the
current time of day, which is useless, and which the filters could just as
easily query for themselves.
patch by Bobby Bingham, uhmmmm gmail com
author | diego |
---|---|
date | Thu, 29 Mar 2007 05:24:35 +0000 |
parents | 11c57b75bccd |
children | b7950418654d |
rev | line source |
---|---|
1183 | 1 /* |
2 * GXF muxer. | |
3 * Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>. | |
4 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1322
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1322
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1322
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or modify |
1183 | 8 * it under the terms of the GNU General Public License as published by |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1322
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
1183 | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
1698 | 18 * along with FFmpeg; if not, write to the Free Software |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1322
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
1183 | 20 */ |
21 | |
22 #include "avformat.h" | |
23 #include "gxf.h" | |
24 #include "riff.h" | |
1322
95f56c7b24eb
* Moving FifoBuffer out of libavformat/avformat.h and
romansh
parents:
1262
diff
changeset
|
25 #include "fifo.h" |
1183 | 26 |
27 #define GXF_AUDIO_PACKET_SIZE 65536 | |
28 | |
29 typedef struct GXFStreamContext { | |
30 AVCodecContext *codec; | |
1322
95f56c7b24eb
* Moving FifoBuffer out of libavformat/avformat.h and
romansh
parents:
1262
diff
changeset
|
31 AVFifoBuffer audio_buffer; |
1183 | 32 uint32_t track_type; |
33 uint32_t sample_size; | |
34 uint32_t sample_rate; | |
35 uint16_t media_type; | |
36 uint16_t media_info; | |
37 uint8_t index; | |
38 int frame_rate_index; | |
39 int lines_index; | |
40 int fields; | |
41 int iframes; | |
42 int pframes; | |
43 int bframes; | |
44 int p_per_gop; | |
45 int b_per_gop; | |
1261 | 46 int first_gop_closed; |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
47 int64_t current_dts; |
1542 | 48 int dts_delay; |
1183 | 49 } GXFStreamContext; |
50 | |
51 typedef struct GXFContext { | |
52 uint32_t nb_frames; | |
53 uint32_t material_flags; | |
54 uint16_t audio_tracks; | |
55 uint16_t mpeg_tracks; | |
56 int64_t creation_time; | |
57 uint32_t umf_start_offset; | |
58 uint32_t umf_track_offset; | |
59 uint32_t umf_media_offset; | |
60 uint32_t umf_user_data_offset; | |
61 uint32_t umf_user_data_size; | |
62 uint32_t umf_length; | |
63 uint16_t umf_track_size; | |
64 uint16_t umf_media_size; | |
65 int audio_written; | |
66 int sample_rate; | |
67 int flags; | |
68 AVFormatContext *fc; | |
69 GXFStreamContext streams[48]; | |
70 } GXFContext; | |
71 | |
72 typedef struct GXF_Lines { | |
73 int height; | |
74 int index; | |
75 } GXF_Lines; | |
76 | |
77 | |
78 /* FIXME check if it is relevant */ | |
79 static const GXF_Lines gxf_lines_tab[] = { | |
80 { 480, 1 }, /* NTSC */ | |
81 { 512, 1 }, /* NTSC + VBI */ | |
82 { 576, 2 }, /* PAL */ | |
83 { 608, 2 }, /* PAL + VBI */ | |
84 { 1080, 4 }, | |
85 { 720, 6 }, | |
86 }; | |
87 | |
1677
2a85c82b8538
add codec_id <-> codec_tag tables to AVIn/OutputFormat
michael
parents:
1542
diff
changeset
|
88 static const AVCodecTag gxf_media_types[] = { |
1183 | 89 { CODEC_ID_MJPEG , 3 }, /* NTSC */ |
90 { CODEC_ID_MJPEG , 4 }, /* PAL */ | |
91 { CODEC_ID_PCM_S24LE , 9 }, | |
92 { CODEC_ID_PCM_S16LE , 10 }, | |
93 { CODEC_ID_MPEG2VIDEO, 11 }, /* NTSC */ | |
94 { CODEC_ID_MPEG2VIDEO, 12 }, /* PAL */ | |
95 { CODEC_ID_DVVIDEO , 13 }, /* NTSC */ | |
96 { CODEC_ID_DVVIDEO , 14 }, /* PAL */ | |
97 { CODEC_ID_DVVIDEO , 15 }, /* 50M NTSC */ | |
98 { CODEC_ID_DVVIDEO , 16 }, /* 50M PAL */ | |
99 { CODEC_ID_AC3 , 17 }, | |
100 //{ CODEC_ID_NONE, , 18 }, /* Non compressed 24 bit audio */ | |
101 { CODEC_ID_MPEG2VIDEO, 20 }, /* MPEG HD */ | |
102 { CODEC_ID_MPEG1VIDEO, 22 }, /* NTSC */ | |
103 { CODEC_ID_MPEG1VIDEO, 23 }, /* PAL */ | |
104 { 0, 0 }, | |
105 }; | |
106 | |
107 #define SERVER_PATH "/space/" | |
108 #define ES_NAME_PATTERN "ES." | |
109 | |
110 static int gxf_find_lines_index(GXFStreamContext *ctx) | |
111 { | |
112 int i; | |
113 | |
114 for (i = 0; i < 6; ++i) { | |
115 if (ctx->codec->height == gxf_lines_tab[i].height) { | |
116 ctx->lines_index = gxf_lines_tab[i].index; | |
117 return 0; | |
118 } | |
119 } | |
120 return -1; | |
121 } | |
122 | |
123 static void gxf_write_padding(ByteIOContext *pb, offset_t to_pad) | |
124 { | |
1213 | 125 for (; to_pad > 0; to_pad--) { |
1183 | 126 put_byte(pb, 0); |
127 } | |
128 } | |
129 | |
130 static offset_t updatePacketSize(ByteIOContext *pb, offset_t pos) | |
131 { | |
132 offset_t curpos; | |
133 int size; | |
134 | |
135 size = url_ftell(pb) - pos; | |
136 if (size % 4) { | |
137 gxf_write_padding(pb, 4 - size % 4); | |
138 size = url_ftell(pb) - pos; | |
139 } | |
140 curpos = url_ftell(pb); | |
141 url_fseek(pb, pos + 6, SEEK_SET); | |
142 put_be32(pb, size); | |
143 url_fseek(pb, curpos, SEEK_SET); | |
144 return curpos - pos; | |
145 } | |
146 | |
147 static offset_t updateSize(ByteIOContext *pb, offset_t pos) | |
148 { | |
149 offset_t curpos; | |
150 | |
151 curpos = url_ftell(pb); | |
152 url_fseek(pb, pos, SEEK_SET); | |
153 put_be16(pb, curpos - pos - 2); | |
154 url_fseek(pb, curpos, SEEK_SET); | |
155 return curpos - pos; | |
156 } | |
157 | |
158 static void gxf_write_packet_header(ByteIOContext *pb, pkt_type_t type) | |
159 { | |
160 put_be32(pb, 0); /* packet leader for synchro */ | |
161 put_byte(pb, 1); | |
162 put_byte(pb, type); /* map packet */ | |
163 put_be32(pb, 0); /* size */ | |
164 put_be32(pb, 0); /* reserved */ | |
165 put_byte(pb, 0xE1); /* trailer 1 */ | |
166 put_byte(pb, 0xE2); /* trailer 2 */ | |
167 } | |
168 | |
169 static int gxf_write_mpeg_auxiliary(ByteIOContext *pb, GXFStreamContext *ctx) | |
170 { | |
171 char buffer[1024]; | |
172 int size; | |
173 | |
174 if (ctx->iframes) { | |
175 ctx->p_per_gop = ctx->pframes / ctx->iframes; | |
176 if (ctx->pframes % ctx->iframes) | |
177 ctx->p_per_gop++; | |
178 if (ctx->pframes) | |
179 ctx->b_per_gop = ctx->bframes / ctx->pframes; | |
180 if (ctx->p_per_gop > 9) | |
181 ctx->p_per_gop = 9; /* ensure value won't take more than one char */ | |
182 if (ctx->b_per_gop > 9) | |
183 ctx->b_per_gop = 9; /* ensure value won't take more than one char */ | |
184 } | |
185 size = snprintf(buffer, 1024, "Ver 1\nBr %.6f\nIpg 1\nPpi %d\nBpiop %d\n" | |
1247
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
186 "Pix 0\nCf %d\nCg %d\nSl 7\nnl16 %d\nVi 1\nf1 1\n", |
1183 | 187 (float)ctx->codec->bit_rate, ctx->p_per_gop, ctx->b_per_gop, |
1262 | 188 ctx->codec->pix_fmt == PIX_FMT_YUV422P ? 2 : 1, ctx->first_gop_closed == 1, |
1183 | 189 ctx->codec->height / 16); |
190 put_byte(pb, 0x4F); | |
191 put_byte(pb, size + 1); | |
192 put_buffer(pb, (uint8_t *)buffer, size + 1); | |
193 return size + 3; | |
194 } | |
195 | |
196 static int gxf_write_timecode_auxiliary(ByteIOContext *pb, GXFStreamContext *ctx) | |
197 { | |
198 /* FIXME implement that */ | |
199 put_byte(pb, 0); /* fields */ | |
200 put_byte(pb, 0); /* seconds */ | |
201 put_byte(pb, 0); /* minutes */ | |
202 put_byte(pb, 0); /* flags + hours */ | |
203 /* reserved */ | |
204 put_be32(pb, 0); | |
205 return 8; | |
206 } | |
207 | |
208 static int gxf_write_track_description(ByteIOContext *pb, GXFStreamContext *stream) | |
209 { | |
210 offset_t pos; | |
211 | |
212 /* track description section */ | |
213 put_byte(pb, stream->media_type + 0x80); | |
214 put_byte(pb, stream->index + 0xC0); | |
215 | |
216 pos = url_ftell(pb); | |
217 put_be16(pb, 0); /* size */ | |
218 | |
219 /* media file name */ | |
220 put_byte(pb, 0x4C); | |
221 put_byte(pb, strlen(ES_NAME_PATTERN) + 3); | |
222 put_tag(pb, ES_NAME_PATTERN); | |
223 put_be16(pb, stream->media_info); | |
224 put_byte(pb, 0); | |
225 | |
226 if (stream->codec->codec_id != CODEC_ID_MPEG2VIDEO) { | |
227 /* auxiliary information */ | |
228 put_byte(pb, 0x4D); | |
229 put_byte(pb, 8); | |
230 if (stream->codec->codec_id == CODEC_ID_NONE) | |
231 gxf_write_timecode_auxiliary(pb, stream); | |
232 else | |
233 put_le64(pb, 0); | |
234 } | |
235 | |
236 /* file system version */ | |
237 put_byte(pb, 0x4E); | |
238 put_byte(pb, 4); | |
239 put_be32(pb, 0); | |
240 | |
241 if (stream->codec->codec_id == CODEC_ID_MPEG2VIDEO) | |
242 gxf_write_mpeg_auxiliary(pb, stream); | |
243 | |
244 /* frame rate */ | |
245 put_byte(pb, 0x50); | |
246 put_byte(pb, 4); | |
247 put_be32(pb, stream->frame_rate_index); | |
248 | |
249 /* lines per frame */ | |
250 put_byte(pb, 0x51); | |
251 put_byte(pb, 4); | |
252 put_be32(pb, stream->lines_index); | |
253 | |
254 /* fields per frame */ | |
255 put_byte(pb, 0x52); | |
256 put_byte(pb, 4); | |
257 put_be32(pb, stream->fields); | |
258 | |
259 return updateSize(pb, pos); | |
260 } | |
261 | |
262 static int gxf_write_material_data_section(ByteIOContext *pb, GXFContext *ctx) | |
263 { | |
264 offset_t pos; | |
265 const char *filename = strrchr(ctx->fc->filename, '/'); | |
266 | |
267 pos = url_ftell(pb); | |
268 put_be16(pb, 0); /* size */ | |
269 | |
270 /* name */ | |
271 if (filename) | |
272 filename++; | |
273 else | |
274 filename = ctx->fc->filename; | |
275 put_byte(pb, 0x40); | |
276 put_byte(pb, strlen(SERVER_PATH) + strlen(filename) + 1); | |
277 put_tag(pb, SERVER_PATH); | |
278 put_tag(pb, filename); | |
279 put_byte(pb, 0); | |
280 | |
281 /* first field */ | |
282 put_byte(pb, 0x41); | |
283 put_byte(pb, 4); | |
284 put_be32(pb, 0); | |
285 | |
286 /* last field */ | |
287 put_byte(pb, 0x42); | |
288 put_byte(pb, 4); | |
289 put_be32(pb, ctx->nb_frames); | |
290 | |
291 /* reserved */ | |
292 put_byte(pb, 0x43); | |
293 put_byte(pb, 4); | |
294 put_be32(pb, 0); | |
295 | |
296 put_byte(pb, 0x44); | |
297 put_byte(pb, 4); | |
298 put_be32(pb, ctx->nb_frames); | |
299 | |
300 /* estimated size */ | |
301 put_byte(pb, 0x45); | |
302 put_byte(pb, 4); | |
303 put_be32(pb, url_fsize(pb) / 1024); | |
304 | |
305 return updateSize(pb, pos); | |
306 } | |
307 | |
308 static int gxf_write_track_description_section(ByteIOContext *pb, GXFContext *ctx) | |
309 { | |
310 offset_t pos; | |
311 int i; | |
312 | |
313 pos = url_ftell(pb); | |
314 put_be16(pb, 0); /* size */ | |
315 for (i = 0; i < ctx->fc->nb_streams; ++i) | |
316 gxf_write_track_description(pb, &ctx->streams[i]); | |
317 return updateSize(pb, pos); | |
318 } | |
319 | |
320 static int gxf_write_map_packet(ByteIOContext *pb, GXFContext *ctx) | |
321 { | |
322 offset_t pos = url_ftell(pb); | |
323 | |
324 gxf_write_packet_header(pb, PKT_MAP); | |
325 | |
326 /* preamble */ | |
327 put_byte(pb, 0xE0); /* version */ | |
328 put_byte(pb, 0xFF); /* reserved */ | |
329 | |
330 gxf_write_material_data_section(pb, ctx); | |
331 gxf_write_track_description_section(pb, ctx); | |
332 | |
333 return updatePacketSize(pb, pos); | |
334 } | |
335 | |
336 #if 0 | |
337 static int gxf_write_flt_packet(ByteIOContext *pb, GXFContext *ctx) | |
338 { | |
339 offset_t pos = url_ftell(pb); | |
340 int i; | |
341 | |
342 gxf_write_packet_header(pb, PKT_FLT); | |
343 | |
344 put_le32(pb, 1000); /* number of fields */ | |
345 put_le32(pb, 0); /* number of active flt entries */ | |
346 | |
347 for (i = 0; i < 1000; ++i) { | |
348 put_le32(pb, 0); | |
349 } | |
350 return updatePacketSize(pb, pos); | |
351 } | |
352 #endif | |
353 | |
354 static int gxf_write_umf_material_description(ByteIOContext *pb, GXFContext *ctx) | |
355 { | |
356 put_le32(pb, ctx->flags); | |
357 put_le32(pb, ctx->nb_frames); /* length of the longest track */ | |
358 put_le32(pb, ctx->nb_frames); /* length of the shortest track */ | |
359 put_le32(pb, 0); /* mark in */ | |
360 put_le32(pb, ctx->nb_frames); /* mark out */ | |
361 put_le32(pb, 0); /* timecode mark in */ | |
362 put_le32(pb, ctx->nb_frames); /* timecode mark out */ | |
363 put_le64(pb, ctx->fc->timestamp); /* modification time */ | |
364 put_le64(pb, ctx->fc->timestamp); /* creation time */ | |
365 put_le16(pb, 0); /* reserved */ | |
366 put_le16(pb, 0); /* reserved */ | |
367 put_le16(pb, ctx->audio_tracks); | |
368 put_le16(pb, 0); /* timecode track count */ | |
369 put_le16(pb, 0); /* reserved */ | |
370 put_le16(pb, ctx->mpeg_tracks); | |
371 return 48; | |
372 } | |
373 | |
374 static int gxf_write_umf_payload(ByteIOContext *pb, GXFContext *ctx) | |
375 { | |
376 put_le32(pb, ctx->umf_length); /* total length of the umf data */ | |
377 put_le32(pb, 3); /* version */ | |
378 put_le32(pb, ctx->fc->nb_streams); | |
379 put_le32(pb, ctx->umf_track_offset); /* umf track section offset */ | |
380 put_le32(pb, ctx->umf_track_size); | |
381 put_le32(pb, ctx->fc->nb_streams); | |
382 put_le32(pb, ctx->umf_media_offset); | |
383 put_le32(pb, ctx->umf_media_size); | |
384 put_le32(pb, ctx->umf_user_data_offset); /* user data offset */ | |
385 put_le32(pb, ctx->umf_user_data_size); /* user data size */ | |
386 put_le32(pb, 0); /* reserved */ | |
387 put_le32(pb, 0); /* reserved */ | |
388 return 48; | |
389 } | |
390 | |
391 static int gxf_write_umf_track_description(ByteIOContext *pb, GXFContext *ctx) | |
392 { | |
393 offset_t pos = url_ftell(pb); | |
394 int tracks[255]={0}; | |
395 int i; | |
396 | |
397 ctx->umf_track_offset = pos - ctx->umf_start_offset; | |
398 for (i = 0; i < ctx->fc->nb_streams; ++i) { | |
399 AVStream *st = ctx->fc->streams[i]; | |
400 GXFStreamContext *sc = &ctx->streams[i]; | |
401 int id = 0; | |
402 | |
403 switch (st->codec->codec_id) { | |
404 case CODEC_ID_MPEG1VIDEO: id= 'L'; break; | |
405 case CODEC_ID_MPEG2VIDEO: id= 'M'; break; | |
406 case CODEC_ID_PCM_S16LE: id= 'A'; break; | |
407 case CODEC_ID_DVVIDEO: id= sc->track_type == 6 ? 'E' : 'D'; break; | |
408 case CODEC_ID_MJPEG: id= 'V'; break; | |
1361
37baab7af15a
quiet gcc about enum value not handled in switch
bcoudurier
parents:
1358
diff
changeset
|
409 default: break; |
1183 | 410 } |
411 sc->media_info= id << 8; | |
412 /* FIXME first 10 audio tracks are 0 to 9 next 22 are A to V */ | |
413 sc->media_info |= '0' + (tracks[id]++); | |
414 put_le16(pb, sc->media_info); | |
415 put_le16(pb, 1); | |
416 } | |
417 return url_ftell(pb) - pos; | |
418 } | |
419 | |
420 static int gxf_write_umf_media_mpeg(ByteIOContext *pb, GXFStreamContext *stream) | |
421 { | |
422 if (stream->codec->pix_fmt == PIX_FMT_YUV422P) | |
423 put_le32(pb, 2); | |
424 else | |
425 put_le32(pb, 1); /* default to 420 */ | |
1262 | 426 put_le32(pb, stream->first_gop_closed == 1); /* closed = 1, open = 0, unknown = 255 */ |
1183 | 427 put_le32(pb, 3); /* top = 1, bottom = 2, frame = 3, unknown = 0 */ |
428 put_le32(pb, 1); /* I picture per GOP */ | |
429 put_le32(pb, stream->p_per_gop); | |
430 put_le32(pb, stream->b_per_gop); | |
431 if (stream->codec->codec_id == CODEC_ID_MPEG2VIDEO) | |
432 put_le32(pb, 2); | |
433 else if (stream->codec->codec_id == CODEC_ID_MPEG1VIDEO) | |
434 put_le32(pb, 1); | |
435 else | |
436 put_le32(pb, 0); | |
437 put_le32(pb, 0); /* reserved */ | |
438 return 32; | |
439 } | |
440 | |
441 static int gxf_write_umf_media_timecode(ByteIOContext *pb, GXFStreamContext *track) | |
442 { | |
443 /* FIXME implement */ | |
444 put_be32(pb, 0); /* drop frame flag */ | |
445 put_be32(pb, 0); /* reserved */ | |
446 put_be32(pb, 0); /* reserved */ | |
447 put_be32(pb, 0); /* reserved */ | |
448 put_be32(pb, 0); /* reserved */ | |
449 put_be32(pb, 0); /* reserved */ | |
450 put_be32(pb, 0); /* reserved */ | |
451 put_be32(pb, 0); /* reserved */ | |
452 return 32; | |
453 } | |
454 | |
455 static int gxf_write_umf_media_dv(ByteIOContext *pb, GXFStreamContext *track) | |
456 { | |
457 int i; | |
458 | |
459 for (i = 0; i < 8; i++) { | |
460 put_be32(pb, 0); | |
461 } | |
462 return 32; | |
463 } | |
464 | |
465 static int gxf_write_umf_media_audio(ByteIOContext *pb, GXFStreamContext *track) | |
466 { | |
467 put_le64(pb, av_dbl2int(1)); /* sound level to begin to */ | |
468 put_le64(pb, av_dbl2int(1)); /* sound level to begin to */ | |
469 put_le32(pb, 0); /* number of fields over which to ramp up sound level */ | |
470 put_le32(pb, 0); /* number of fields over which to ramp down sound level */ | |
471 put_le32(pb, 0); /* reserved */ | |
472 put_le32(pb, 0); /* reserved */ | |
473 return 32; | |
474 } | |
475 | |
476 #if 0 | |
477 static int gxf_write_umf_media_mjpeg(ByteIOContext *pb, GXFStreamContext *track) | |
478 { | |
479 put_be64(pb, 0); /* FIXME FLOAT max chroma quant level */ | |
480 put_be64(pb, 0); /* FIXME FLOAT max luma quant level */ | |
481 put_be64(pb, 0); /* FIXME FLOAT min chroma quant level */ | |
482 put_be64(pb, 0); /* FIXME FLOAT min luma quant level */ | |
483 return 32; | |
484 } | |
485 #endif | |
486 | |
487 static int gxf_write_umf_media_description(ByteIOContext *pb, GXFContext *ctx) | |
488 { | |
489 offset_t pos; | |
490 int i; | |
491 | |
492 pos = url_ftell(pb); | |
493 ctx->umf_media_offset = pos - ctx->umf_start_offset; | |
494 for (i = 0; i < ctx->fc->nb_streams; ++i) { | |
495 GXFStreamContext *sc = &ctx->streams[i]; | |
496 char buffer[88]; | |
497 offset_t startpos, curpos; | |
498 int path_size = strlen(ES_NAME_PATTERN); | |
499 | |
1260 | 500 memset(buffer, 0, 88); |
1183 | 501 startpos = url_ftell(pb); |
502 put_le16(pb, 0); /* length */ | |
503 put_le16(pb, sc->media_info); | |
504 put_le16(pb, 0); /* reserved */ | |
505 put_le16(pb, 0); /* reserved */ | |
506 put_le32(pb, ctx->nb_frames); | |
507 put_le32(pb, 0); /* attributes rw, ro */ | |
508 put_le32(pb, 0); /* mark in */ | |
509 put_le32(pb, ctx->nb_frames); /* mark out */ | |
510 strncpy(buffer, ES_NAME_PATTERN, path_size); | |
511 put_buffer(pb, (uint8_t *)buffer, path_size); | |
512 put_be16(pb, sc->media_info); | |
513 put_buffer(pb, (uint8_t *)buffer + path_size + 2, 88 - path_size - 2); | |
514 put_le32(pb, sc->track_type); | |
515 put_le32(pb, sc->sample_rate); | |
516 put_le32(pb, sc->sample_size); | |
517 put_le32(pb, 0); /* reserved */ | |
518 switch (sc->codec->codec_id) { | |
519 case CODEC_ID_MPEG2VIDEO: | |
520 gxf_write_umf_media_mpeg(pb, sc); | |
521 break; | |
522 case CODEC_ID_PCM_S16LE: | |
523 gxf_write_umf_media_audio(pb, sc); | |
524 break; | |
525 case CODEC_ID_DVVIDEO: | |
526 gxf_write_umf_media_dv(pb, sc); | |
527 break; | |
528 default: | |
529 gxf_write_umf_media_timecode(pb, sc); /* 8 0bytes */ | |
530 } | |
531 curpos = url_ftell(pb); | |
532 url_fseek(pb, startpos, SEEK_SET); | |
533 put_le16(pb, curpos - startpos); | |
534 url_fseek(pb, curpos, SEEK_SET); | |
535 } | |
536 return url_ftell(pb) - pos; | |
537 } | |
538 | |
539 static int gxf_write_umf_user_data(ByteIOContext *pb, GXFContext *ctx) | |
540 { | |
541 offset_t pos = url_ftell(pb); | |
542 ctx->umf_user_data_offset = pos - ctx->umf_start_offset; | |
543 put_le32(pb, 20); | |
544 put_le32(pb, 0); | |
545 put_le16(pb, 0); | |
546 put_le16(pb, 0); | |
547 put_le32(pb, 0); | |
548 put_byte(pb, 0); | |
549 put_byte(pb, 0); | |
550 put_byte(pb, 0); | |
551 put_byte(pb, 0); | |
552 return 20; | |
553 } | |
554 | |
555 static int gxf_write_umf_packet(ByteIOContext *pb, GXFContext *ctx) | |
556 { | |
557 offset_t pos = url_ftell(pb); | |
558 | |
559 gxf_write_packet_header(pb, PKT_UMF); | |
560 | |
561 /* preamble */ | |
562 put_byte(pb, 3); /* first and last (only) packet */ | |
563 put_be32(pb, ctx->umf_length); /* data length */ | |
564 | |
565 ctx->umf_start_offset = url_ftell(pb); | |
566 gxf_write_umf_payload(pb, ctx); | |
567 gxf_write_umf_material_description(pb, ctx); | |
568 ctx->umf_track_size = gxf_write_umf_track_description(pb, ctx); | |
569 ctx->umf_media_size = gxf_write_umf_media_description(pb, ctx); | |
570 ctx->umf_user_data_size = gxf_write_umf_user_data(pb, ctx); | |
571 ctx->umf_length = url_ftell(pb) - ctx->umf_start_offset; | |
572 return updatePacketSize(pb, pos); | |
573 } | |
574 | |
1794 | 575 #define GXF_NODELAY -5000 |
576 | |
1183 | 577 static int gxf_write_header(AVFormatContext *s) |
578 { | |
579 ByteIOContext *pb = &s->pb; | |
580 GXFContext *gxf = s->priv_data; | |
581 int i; | |
582 | |
583 gxf->fc = s; | |
584 gxf->flags |= 0x00080000; /* material is simple clip */ | |
585 for (i = 0; i < s->nb_streams; ++i) { | |
586 AVStream *st = s->streams[i]; | |
587 GXFStreamContext *sc = &gxf->streams[i]; | |
588 | |
589 sc->codec = st->codec; | |
590 sc->index = i; | |
591 sc->media_type = codec_get_tag(gxf_media_types, sc->codec->codec_id); | |
592 if (st->codec->codec_type == CODEC_TYPE_AUDIO) { | |
593 if (st->codec->codec_id != CODEC_ID_PCM_S16LE) { | |
594 av_log(s, AV_LOG_ERROR, "only 16 BIT PCM LE allowed for now\n"); | |
595 return -1; | |
596 } | |
597 if (st->codec->sample_rate != 48000) { | |
598 av_log(s, AV_LOG_ERROR, "only 48000hz sampling rate is allowed\n"); | |
599 return -1; | |
600 } | |
601 if (st->codec->channels != 1) { | |
602 av_log(s, AV_LOG_ERROR, "only mono tracks are allowed\n"); | |
603 return -1; | |
604 } | |
605 sc->track_type = 2; | |
606 sc->sample_rate = st->codec->sample_rate; | |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
607 av_set_pts_info(st, 64, 1, sc->sample_rate); |
1183 | 608 sc->sample_size = 16; |
609 sc->frame_rate_index = -2; | |
610 sc->lines_index = -2; | |
611 sc->fields = -2; | |
612 gxf->audio_tracks++; | |
613 gxf->flags |= 0x04000000; /* audio is 16 bit pcm */ | |
1322
95f56c7b24eb
* Moving FifoBuffer out of libavformat/avformat.h and
romansh
parents:
1262
diff
changeset
|
614 av_fifo_init(&sc->audio_buffer, 3*GXF_AUDIO_PACKET_SIZE); |
1183 | 615 } else if (sc->codec->codec_type == CODEC_TYPE_VIDEO) { |
616 /* FIXME check from time_base ? */ | |
617 if (sc->codec->height == 480 || sc->codec->height == 512) { /* NTSC or NTSC+VBI */ | |
618 sc->frame_rate_index = 5; | |
619 sc->sample_rate = 60; | |
620 gxf->flags |= 0x00000080; | |
621 } else { /* assume PAL */ | |
622 sc->frame_rate_index = 6; | |
623 sc->media_type++; | |
624 sc->sample_rate = 50; | |
625 gxf->flags |= 0x00000040; | |
626 } | |
627 gxf->sample_rate = sc->sample_rate; | |
1794 | 628 av_set_pts_info(st, 64, 1, st->codec->time_base.den); |
629 sc->dts_delay = GXF_NODELAY; | |
1183 | 630 if (gxf_find_lines_index(sc) < 0) |
631 sc->lines_index = -1; | |
632 sc->sample_size = st->codec->bit_rate; | |
633 sc->fields = 2; /* interlaced */ | |
634 switch (sc->codec->codec_id) { | |
635 case CODEC_ID_MPEG2VIDEO: | |
1262 | 636 sc->first_gop_closed = -1; |
1183 | 637 sc->track_type = 4; |
638 gxf->mpeg_tracks++; | |
639 gxf->flags |= 0x00008000; | |
640 break; | |
641 case CODEC_ID_DVVIDEO: | |
642 if (sc->codec->pix_fmt == PIX_FMT_YUV422P) { | |
643 sc->media_type += 2; | |
644 sc->track_type = 6; | |
645 gxf->flags |= 0x00002000; | |
646 } else { | |
647 sc->track_type = 5; | |
648 gxf->flags |= 0x00001000; | |
649 } | |
650 break; | |
651 default: | |
1401 | 652 av_log(s, AV_LOG_ERROR, "video codec not supported\n"); |
1183 | 653 return -1; |
654 } | |
655 } | |
656 } | |
657 gxf_write_map_packet(pb, gxf); | |
658 //gxf_write_flt_packet(pb, gxf); | |
659 gxf_write_umf_packet(pb, gxf); | |
660 put_flush_packet(pb); | |
661 return 0; | |
662 } | |
663 | |
664 static int gxf_write_eos_packet(ByteIOContext *pb, GXFContext *ctx) | |
665 { | |
666 offset_t pos = url_ftell(pb); | |
667 | |
668 gxf_write_packet_header(pb, PKT_EOS); | |
669 return updatePacketSize(pb, pos); | |
670 } | |
671 | |
672 static int gxf_write_trailer(AVFormatContext *s) | |
673 { | |
674 ByteIOContext *pb = &s->pb; | |
675 GXFContext *gxf = s->priv_data; | |
676 offset_t end; | |
677 int i; | |
678 | |
679 for (i = 0; i < s->nb_streams; ++i) { | |
680 if (s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) { | |
1322
95f56c7b24eb
* Moving FifoBuffer out of libavformat/avformat.h and
romansh
parents:
1262
diff
changeset
|
681 av_fifo_free(&gxf->streams[i].audio_buffer); |
1183 | 682 } |
683 if (s->streams[i]->codec->frame_number > gxf->nb_frames) | |
684 gxf->nb_frames = 2 * s->streams[i]->codec->frame_number; | |
685 } | |
686 | |
687 gxf_write_eos_packet(pb, gxf); | |
688 end = url_ftell(pb); | |
689 url_fseek(pb, 0, SEEK_SET); | |
690 /* overwrite map and umf packets with new values */ | |
691 gxf_write_map_packet(pb, gxf); | |
692 //gxf_write_flt_packet(pb, gxf); | |
693 gxf_write_umf_packet(pb, gxf); | |
694 url_fseek(pb, end, SEEK_SET); | |
695 return 0; | |
696 } | |
697 | |
1247
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
698 static int gxf_parse_mpeg_frame(GXFStreamContext *sc, const uint8_t *buf, int size) |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
699 { |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
700 uint32_t c=-1; |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
701 int i; |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
702 for(i=0; i<size-4 && c!=0x100; i++){ |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
703 c = (c<<8) + buf[i]; |
1262 | 704 if(c == 0x1B8 && sc->first_gop_closed == -1) /* GOP start code */ |
1261 | 705 sc->first_gop_closed= (buf[i+4]>>6)&1; |
1247
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
706 } |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
707 return (buf[i+1]>>3)&7; |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
708 } |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
709 |
1183 | 710 static int gxf_write_media_preamble(ByteIOContext *pb, GXFContext *ctx, AVPacket *pkt, int size) |
711 { | |
712 GXFStreamContext *sc = &ctx->streams[pkt->stream_index]; | |
1794 | 713 int64_t dts = av_rescale(pkt->dts, ctx->sample_rate, sc->codec->time_base.den); |
1183 | 714 |
715 put_byte(pb, sc->media_type); | |
716 put_byte(pb, sc->index); | |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
717 put_be32(pb, dts); |
1183 | 718 if (sc->codec->codec_type == CODEC_TYPE_AUDIO) { |
719 put_be16(pb, 0); | |
720 put_be16(pb, size / 2); | |
721 } else if (sc->codec->codec_id == CODEC_ID_MPEG2VIDEO) { | |
1247
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
722 int frame_type = gxf_parse_mpeg_frame(sc, pkt->data, pkt->size); |
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
723 if (frame_type == FF_I_TYPE) { |
1183 | 724 put_byte(pb, 0x0d); |
725 sc->iframes++; | |
1247
2f118b3e65c6
parse mpeg frame to get pict type and closed gop flag
bcoudurier
parents:
1213
diff
changeset
|
726 } else if (frame_type == FF_B_TYPE) { |
1183 | 727 put_byte(pb, 0x0f); |
728 sc->bframes++; | |
729 } else { | |
730 put_byte(pb, 0x0e); | |
731 sc->pframes++; | |
732 } | |
733 put_be24(pb, size); | |
734 } else if (sc->codec->codec_id == CODEC_ID_DVVIDEO) { | |
735 put_byte(pb, size / 4096); | |
736 put_be24(pb, 0); | |
737 } else | |
738 put_be32(pb, size); | |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
739 put_be32(pb, dts); |
1183 | 740 put_byte(pb, 1); /* flags */ |
741 put_byte(pb, 0); /* reserved */ | |
742 return 16; | |
743 } | |
744 | |
745 static int gxf_write_media_packet(ByteIOContext *pb, GXFContext *ctx, AVPacket *pkt) | |
746 { | |
747 GXFStreamContext *sc = &ctx->streams[pkt->stream_index]; | |
748 offset_t pos = url_ftell(pb); | |
749 int padding = 0; | |
750 | |
751 gxf_write_packet_header(pb, PKT_MEDIA); | |
752 if (sc->codec->codec_id == CODEC_ID_MPEG2VIDEO && pkt->size % 4) /* MPEG-2 frames must be padded */ | |
753 padding = 4 - pkt->size % 4; | |
1212 | 754 else if (sc->codec->codec_type == CODEC_TYPE_AUDIO) |
755 padding = GXF_AUDIO_PACKET_SIZE - pkt->size; | |
1183 | 756 gxf_write_media_preamble(pb, ctx, pkt, pkt->size + padding); |
1212 | 757 put_buffer(pb, pkt->data, pkt->size); |
758 gxf_write_padding(pb, padding); | |
1183 | 759 return updatePacketSize(pb, pos); |
760 } | |
761 | |
762 static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt) | |
763 { | |
764 GXFContext *gxf = s->priv_data; | |
765 | |
766 gxf_write_media_packet(&s->pb, gxf, pkt); | |
767 put_flush_packet(&s->pb); | |
768 return 0; | |
769 } | |
770 | |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
771 static int gxf_new_audio_packet(GXFContext *gxf, GXFStreamContext *sc, AVPacket *pkt, int flush) |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
772 { |
1322
95f56c7b24eb
* Moving FifoBuffer out of libavformat/avformat.h and
romansh
parents:
1262
diff
changeset
|
773 int size = flush ? av_fifo_size(&sc->audio_buffer) : GXF_AUDIO_PACKET_SIZE; |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
774 |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
775 if (!size) |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
776 return 0; |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
777 av_new_packet(pkt, size); |
1322
95f56c7b24eb
* Moving FifoBuffer out of libavformat/avformat.h and
romansh
parents:
1262
diff
changeset
|
778 av_fifo_read(&sc->audio_buffer, pkt->data, size); |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
779 pkt->stream_index = sc->index; |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
780 pkt->dts = sc->current_dts; |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
781 sc->current_dts += size / 2; /* we only support 16 bit pcm mono for now */ |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
782 return size; |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
783 } |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
784 |
1183 | 785 static int gxf_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush) |
786 { | |
787 GXFContext *gxf = s->priv_data; | |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
788 AVPacket new_pkt; |
1183 | 789 int i; |
790 | |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
791 for (i = 0; i < s->nb_streams; i++) { |
1542 | 792 AVStream *st = s->streams[i]; |
793 GXFStreamContext *sc = &gxf->streams[i]; | |
794 if (st->codec->codec_type == CODEC_TYPE_AUDIO) { | |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
795 if (pkt && pkt->stream_index == i) { |
1322
95f56c7b24eb
* Moving FifoBuffer out of libavformat/avformat.h and
romansh
parents:
1262
diff
changeset
|
796 av_fifo_write(&sc->audio_buffer, pkt->data, pkt->size); |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
797 pkt = NULL; |
1183 | 798 } |
1322
95f56c7b24eb
* Moving FifoBuffer out of libavformat/avformat.h and
romansh
parents:
1262
diff
changeset
|
799 if (flush || av_fifo_size(&sc->audio_buffer) >= GXF_AUDIO_PACKET_SIZE) { |
1398 | 800 if (!pkt && gxf_new_audio_packet(gxf, sc, &new_pkt, flush) > 0) { |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
801 pkt = &new_pkt; |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
802 break; /* add pkt right now into list */ |
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
803 } |
1183 | 804 } |
1794 | 805 } else if (pkt && pkt->stream_index == i) { |
806 if (sc->dts_delay == GXF_NODELAY) /* adjust dts if needed */ | |
807 sc->dts_delay = pkt->dts; | |
1542 | 808 pkt->dts -= sc->dts_delay; |
1183 | 809 } |
810 } | |
1253
f3d5e1c49875
use packet dts as correct media field number and use av_interleave_pkt_per_dts
bcoudurier
parents:
1247
diff
changeset
|
811 return av_interleave_packet_per_dts(s, out, pkt, flush); |
1183 | 812 } |
813 | |
814 AVOutputFormat gxf_muxer = { | |
815 "gxf", | |
816 "GXF format", | |
817 NULL, | |
818 "gxf", | |
819 sizeof(GXFContext), | |
820 CODEC_ID_PCM_S16LE, | |
821 CODEC_ID_MPEG2VIDEO, | |
822 gxf_write_header, | |
823 gxf_write_packet, | |
824 gxf_write_trailer, | |
825 0, | |
826 NULL, | |
827 gxf_interleave_packet, | |
828 }; |