comparison mpeg.c @ 335:b0ac206f232d libavformat

better and simpler logic for MPEG muxing - fixed rare MPEG muxing PTS generation bug (stuffing is added in such rare cases) - fixed AC3 payload size generation - generate correct AC3 frame header (need spec checking)
author bellard
date Tue, 16 Dec 2003 11:25:30 +0000
parents 4530681af424
children d75fd4c6ab62
comparison
equal deleted inserted replaced
334:7f089db11f9a 335:b0ac206f232d
22 //#define DEBUG_SEEK 22 //#define DEBUG_SEEK
23 23
24 typedef struct { 24 typedef struct {
25 uint8_t buffer[MAX_PAYLOAD_SIZE]; 25 uint8_t buffer[MAX_PAYLOAD_SIZE];
26 int buffer_ptr; 26 int buffer_ptr;
27 int nb_frames; /* number of starting frame encountered (AC3) */
28 int frame_start_offset; /* starting offset of the frame + 1 (0 if none) */
27 uint8_t id; 29 uint8_t id;
28 int max_buffer_size; /* in bytes */ 30 int max_buffer_size; /* in bytes */
29 int packet_number; 31 int packet_number;
30 int64_t start_pts; 32 int64_t start_pts;
31 int64_t start_dts; 33 int64_t start_dts;
32 } StreamInfo; 34 } StreamInfo;
33 35
34 typedef struct { 36 typedef struct {
35 int packet_size; /* required packet size */ 37 int packet_size; /* required packet size */
36 int packet_data_max_size; /* maximum data size inside a packet */
37 int packet_number; 38 int packet_number;
38 int pack_header_freq; /* frequency (in packets^-1) at which we send pack headers */ 39 int pack_header_freq; /* frequency (in packets^-1) at which we send pack headers */
39 int system_header_freq; 40 int system_header_freq;
41 int system_header_size;
40 int mux_rate; /* bitrate in units of 50 bytes/s */ 42 int mux_rate; /* bitrate in units of 50 bytes/s */
41 /* stream info */ 43 /* stream info */
42 int audio_bound; 44 int audio_bound;
43 int video_bound; 45 int video_bound;
44 int is_mpeg2; 46 int is_mpeg2;
164 buf[5] = (size - 6) & 0xff; 166 buf[5] = (size - 6) & 0xff;
165 167
166 return size; 168 return size;
167 } 169 }
168 170
171 static int get_system_header_size(AVFormatContext *ctx)
172 {
173 int buf_index, i, private_stream_coded;
174 StreamInfo *stream;
175
176 buf_index = 12;
177 private_stream_coded = 0;
178 for(i=0;i<ctx->nb_streams;i++) {
179 stream = ctx->streams[i]->priv_data;
180 if (stream->id < 0xc0) {
181 if (private_stream_coded)
182 continue;
183 private_stream_coded = 1;
184 }
185 buf_index += 3;
186 }
187 return buf_index;
188 }
189
169 static int mpeg_mux_init(AVFormatContext *ctx) 190 static int mpeg_mux_init(AVFormatContext *ctx)
170 { 191 {
171 MpegMuxContext *s = ctx->priv_data; 192 MpegMuxContext *s = ctx->priv_data;
172 int bitrate, i, mpa_id, mpv_id, ac3_id; 193 int bitrate, i, mpa_id, mpv_id, ac3_id;
173 AVStream *st; 194 AVStream *st;
180 if (s->is_vcd) 201 if (s->is_vcd)
181 s->packet_size = 2324; /* VCD packet size */ 202 s->packet_size = 2324; /* VCD packet size */
182 else 203 else
183 s->packet_size = 2048; 204 s->packet_size = 2048;
184 205
185 /* startcode(4) + length(2) + flags(1) */
186 s->packet_data_max_size = s->packet_size - 7;
187 if (s->is_mpeg2)
188 s->packet_data_max_size -= 2;
189 s->audio_bound = 0; 206 s->audio_bound = 0;
190 s->video_bound = 0; 207 s->video_bound = 0;
191 mpa_id = AUDIO_ID; 208 mpa_id = AUDIO_ID;
192 ac3_id = 0x80; 209 ac3_id = 0x80;
193 mpv_id = VIDEO_ID; 210 mpv_id = VIDEO_ID;
258 stream->buffer_ptr = 0; 275 stream->buffer_ptr = 0;
259 stream->packet_number = 0; 276 stream->packet_number = 0;
260 stream->start_pts = AV_NOPTS_VALUE; 277 stream->start_pts = AV_NOPTS_VALUE;
261 stream->start_dts = AV_NOPTS_VALUE; 278 stream->start_dts = AV_NOPTS_VALUE;
262 } 279 }
280 s->system_header_size = get_system_header_size(ctx);
263 s->last_scr = 0; 281 s->last_scr = 0;
264 return 0; 282 return 0;
265 fail: 283 fail:
266 for(i=0;i<ctx->nb_streams;i++) { 284 for(i=0;i<ctx->nb_streams;i++) {
267 av_free(ctx->streams[i]->priv_data); 285 av_free(ctx->streams[i]->priv_data);
277 1); 295 1);
278 put_be16(pb, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1)); 296 put_be16(pb, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1));
279 put_be16(pb, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1)); 297 put_be16(pb, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1));
280 } 298 }
281 299
300
301 /* return the exact available payload size for the next packet for
302 stream 'stream_index'. 'pts' and 'dts' are only used to know if
303 timestamps are needed in the packet header. */
304 static int get_packet_payload_size(AVFormatContext *ctx, int stream_index,
305 int64_t pts, int64_t dts)
306 {
307 MpegMuxContext *s = ctx->priv_data;
308 int buf_index;
309 StreamInfo *stream;
310
311 buf_index = 0;
312 if (((s->packet_number % s->pack_header_freq) == 0)) {
313 /* pack header size */
314 if (s->is_mpeg2)
315 buf_index += 14;
316 else
317 buf_index += 12;
318 if ((s->packet_number % s->system_header_freq) == 0)
319 buf_index += s->system_header_size;
320 }
321
322 /* packet header size */
323 buf_index += 6;
324 if (s->is_mpeg2)
325 buf_index += 3;
326 if (pts != AV_NOPTS_VALUE) {
327 if (dts != AV_NOPTS_VALUE)
328 buf_index += 5 + 5;
329 else
330 buf_index += 5;
331 } else {
332 if (!s->is_mpeg2)
333 buf_index++;
334 }
335
336 stream = ctx->streams[stream_index]->priv_data;
337 if (stream->id < 0xc0) {
338 /* AC3 private data header */
339 buf_index += 4;
340 }
341 return s->packet_size - buf_index;
342 }
343
282 /* flush the packet on stream stream_index */ 344 /* flush the packet on stream stream_index */
283 static void flush_packet(AVFormatContext *ctx, int stream_index, 345 static void flush_packet(AVFormatContext *ctx, int stream_index,
284 int64_t pts, int64_t dts, int64_t scr) 346 int64_t pts, int64_t dts, int64_t scr)
285 { 347 {
286 MpegMuxContext *s = ctx->priv_data; 348 MpegMuxContext *s = ctx->priv_data;
287 StreamInfo *stream = ctx->streams[stream_index]->priv_data; 349 StreamInfo *stream = ctx->streams[stream_index]->priv_data;
288 uint8_t *buf_ptr; 350 uint8_t *buf_ptr;
289 int size, payload_size, startcode, id, len, stuffing_size, i, header_len; 351 int size, payload_size, startcode, id, stuffing_size, i, header_len;
352 int packet_size;
290 uint8_t buffer[128]; 353 uint8_t buffer[128];
291 354
292 id = stream->id; 355 id = stream->id;
293 356
294 #if 0 357 #if 0
323 } else { 386 } else {
324 if (!s->is_mpeg2) 387 if (!s->is_mpeg2)
325 header_len++; 388 header_len++;
326 } 389 }
327 390
328 payload_size = s->packet_size - (size + 6 + header_len); 391 packet_size = s->packet_size - (size + 6);
392 payload_size = packet_size - header_len;
329 if (id < 0xc0) { 393 if (id < 0xc0) {
330 startcode = PRIVATE_STREAM_1; 394 startcode = PRIVATE_STREAM_1;
331 payload_size -= 4; 395 payload_size -= 4;
332 } else { 396 } else {
333 startcode = 0x100 + id; 397 startcode = 0x100 + id;
334 } 398 }
399
335 stuffing_size = payload_size - stream->buffer_ptr; 400 stuffing_size = payload_size - stream->buffer_ptr;
336 if (stuffing_size < 0) 401 if (stuffing_size < 0)
337 stuffing_size = 0; 402 stuffing_size = 0;
338
339 put_be32(&ctx->pb, startcode); 403 put_be32(&ctx->pb, startcode);
340 404
341 put_be16(&ctx->pb, payload_size + header_len); 405 put_be16(&ctx->pb, packet_size);
342 /* stuffing */ 406 /* stuffing */
343 for(i=0;i<stuffing_size;i++) 407 for(i=0;i<stuffing_size;i++)
344 put_byte(&ctx->pb, 0xff); 408 put_byte(&ctx->pb, 0xff);
345 409
346 if (s->is_mpeg2) { 410 if (s->is_mpeg2) {
375 } 439 }
376 440
377 if (startcode == PRIVATE_STREAM_1) { 441 if (startcode == PRIVATE_STREAM_1) {
378 put_byte(&ctx->pb, id); 442 put_byte(&ctx->pb, id);
379 if (id >= 0x80 && id <= 0xbf) { 443 if (id >= 0x80 && id <= 0xbf) {
380 /* XXX: need to check AC3 spec */ 444 put_byte(&ctx->pb, stream->nb_frames);
381 put_byte(&ctx->pb, 1); 445 put_be16(&ctx->pb, stream->frame_start_offset);
382 put_byte(&ctx->pb, 0);
383 put_byte(&ctx->pb, 2);
384 } 446 }
385 } 447 }
386 448
387 /* output data */ 449 /* output data */
388 put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size); 450 put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size);
389 put_flush_packet(&ctx->pb); 451 put_flush_packet(&ctx->pb);
390 452
391 /* preserve remaining data */
392 len = stream->buffer_ptr - payload_size;
393 if (len < 0)
394 len = 0;
395 memmove(stream->buffer, stream->buffer + stream->buffer_ptr - len, len);
396 stream->buffer_ptr = len;
397
398 s->packet_number++; 453 s->packet_number++;
399 stream->packet_number++; 454 stream->packet_number++;
455 stream->nb_frames = 0;
456 stream->frame_start_offset = 0;
400 } 457 }
401 458
402 static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, 459 static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
403 const uint8_t *buf, int size, int64_t pts) 460 const uint8_t *buf, int size, int64_t pts)
404 { 461 {
405 MpegMuxContext *s = ctx->priv_data; 462 MpegMuxContext *s = ctx->priv_data;
406 AVStream *st = ctx->streams[stream_index]; 463 AVStream *st = ctx->streams[stream_index];
407 StreamInfo *stream = st->priv_data; 464 StreamInfo *stream = st->priv_data;
408 int64_t dts; 465 int64_t dts, new_start_pts, new_start_dts;
409 int len; 466 int len, avail_size;
410 467
411 /* XXX: system clock should be computed precisely, especially for 468 /* XXX: system clock should be computed precisely, especially for
412 CBR case. The current mode gives at least something coherent */ 469 CBR case. The current mode gives at least something coherent */
413 if (stream_index == s->scr_stream_index) 470 if (stream_index == s->scr_stream_index)
414 s->last_scr = pts; 471 s->last_scr = pts;
420 477
421 /* XXX: currently no way to pass dts, will change soon */ 478 /* XXX: currently no way to pass dts, will change soon */
422 dts = AV_NOPTS_VALUE; 479 dts = AV_NOPTS_VALUE;
423 480
424 /* we assume here that pts != AV_NOPTS_VALUE */ 481 /* we assume here that pts != AV_NOPTS_VALUE */
482 new_start_pts = stream->start_pts;
483 new_start_dts = stream->start_dts;
484
425 if (stream->start_pts == AV_NOPTS_VALUE) { 485 if (stream->start_pts == AV_NOPTS_VALUE) {
426 stream->start_pts = pts; 486 new_start_pts = pts;
427 stream->start_dts = dts; 487 new_start_dts = dts;
428 } 488 }
489 avail_size = get_packet_payload_size(ctx, stream_index,
490 new_start_pts,
491 new_start_dts);
492 if (stream->buffer_ptr >= avail_size) {
493 /* unlikely case: outputing the pts or dts increase the packet
494 size so that we cannot write the start of the next
495 packet. In this case, we must flush the current packet with
496 padding */
497 flush_packet(ctx, stream_index,
498 stream->start_pts, stream->start_dts, s->last_scr);
499 stream->buffer_ptr = 0;
500 }
501 stream->start_pts = new_start_pts;
502 stream->start_dts = new_start_dts;
503 stream->nb_frames++;
504 if (stream->frame_start_offset == 0)
505 stream->frame_start_offset = stream->buffer_ptr;
429 while (size > 0) { 506 while (size > 0) {
430 len = s->packet_data_max_size - stream->buffer_ptr; 507 avail_size = get_packet_payload_size(ctx, stream_index,
508 stream->start_pts,
509 stream->start_dts);
510 len = avail_size - stream->buffer_ptr;
431 if (len > size) 511 if (len > size)
432 len = size; 512 len = size;
433 memcpy(stream->buffer + stream->buffer_ptr, buf, len); 513 memcpy(stream->buffer + stream->buffer_ptr, buf, len);
434 stream->buffer_ptr += len; 514 stream->buffer_ptr += len;
435 buf += len; 515 buf += len;
436 size -= len; 516 size -= len;
437 while (stream->buffer_ptr >= s->packet_data_max_size) { 517 if (stream->buffer_ptr >= avail_size) {
438 /* output the packet */ 518 /* if packet full, we send it now */
439 flush_packet(ctx, stream_index, 519 flush_packet(ctx, stream_index,
440 stream->start_pts, stream->start_dts, s->last_scr); 520 stream->start_pts, stream->start_dts, s->last_scr);
521 stream->buffer_ptr = 0;
441 /* Make sure only the FIRST pes packet for this frame has 522 /* Make sure only the FIRST pes packet for this frame has
442 a timestamp */ 523 a timestamp */
443 stream->start_pts = AV_NOPTS_VALUE; 524 stream->start_pts = AV_NOPTS_VALUE;
444 stream->start_dts = AV_NOPTS_VALUE; 525 stream->start_dts = AV_NOPTS_VALUE;
445 } 526 }
446 } 527 }
528
447 return 0; 529 return 0;
448 } 530 }
449 531
450 static int mpeg_mux_end(AVFormatContext *ctx) 532 static int mpeg_mux_end(AVFormatContext *ctx)
451 { 533 {
454 int i; 536 int i;
455 537
456 /* flush each packet */ 538 /* flush each packet */
457 for(i=0;i<ctx->nb_streams;i++) { 539 for(i=0;i<ctx->nb_streams;i++) {
458 stream = ctx->streams[i]->priv_data; 540 stream = ctx->streams[i]->priv_data;
459 while (stream->buffer_ptr > 0) { 541 if (stream->buffer_ptr > 0) {
460 flush_packet(ctx, i, AV_NOPTS_VALUE, AV_NOPTS_VALUE, s->last_scr); 542 /* NOTE: we can always write the remaining data as it was
543 tested before in mpeg_mux_write_packet() */
544 flush_packet(ctx, i, stream->start_pts, stream->start_dts,
545 s->last_scr);
461 } 546 }
462 } 547 }
463 548
464 /* End header according to MPEG1 systems standard. We do not write 549 /* End header according to MPEG1 systems standard. We do not write
465 it as it is usually not needed by decoders and because it 550 it as it is usually not needed by decoders and because it
753 if (st->id == startcode) 838 if (st->id == startcode)
754 goto found; 839 goto found;
755 } 840 }
756 if (startcode >= 0x1e0 && startcode <= 0x1ef) { 841 if (startcode >= 0x1e0 && startcode <= 0x1ef) {
757 type = CODEC_TYPE_VIDEO; 842 type = CODEC_TYPE_VIDEO;
758 codec_id = CODEC_ID_MPEG1VIDEO; 843 codec_id = CODEC_ID_MPEG2VIDEO;
759 } else if (startcode >= 0x1c0 && startcode <= 0x1df) { 844 } else if (startcode >= 0x1c0 && startcode <= 0x1df) {
760 type = CODEC_TYPE_AUDIO; 845 type = CODEC_TYPE_AUDIO;
761 codec_id = CODEC_ID_MP2; 846 codec_id = CODEC_ID_MP2;
762 } else if (startcode >= 0x80 && startcode <= 0x9f) { 847 } else if (startcode >= 0x80 && startcode <= 0x9f) {
763 type = CODEC_TYPE_AUDIO; 848 type = CODEC_TYPE_AUDIO;
992 "MPEG2 PS format (VOB)", 1077 "MPEG2 PS format (VOB)",
993 "video/mpeg", 1078 "video/mpeg",
994 "vob", 1079 "vob",
995 sizeof(MpegMuxContext), 1080 sizeof(MpegMuxContext),
996 CODEC_ID_MP2, 1081 CODEC_ID_MP2,
997 CODEC_ID_MPEG1VIDEO, 1082 CODEC_ID_MPEG2VIDEO,
998 mpeg_mux_init, 1083 mpeg_mux_init,
999 mpeg_mux_write_packet, 1084 mpeg_mux_write_packet,
1000 mpeg_mux_end, 1085 mpeg_mux_end,
1001 }; 1086 };
1002 #endif //CONFIG_ENCODERS 1087 #endif //CONFIG_ENCODERS