Mercurial > libavformat.hg
comparison swf.c @ 1854:0432f6b969b0 libavformat
simplify swf muxer
author | bcoudurier |
---|---|
date | Sun, 04 Mar 2007 22:30:25 +0000 |
parents | 09a67819763e |
children | 908630dcc162 |
comparison
equal
deleted
inserted
replaced
1853:c704f9d730bf | 1854:0432f6b969b0 |
---|---|
69 int swf_frame_number; | 69 int swf_frame_number; |
70 int video_frame_number; | 70 int video_frame_number; |
71 int ms_per_frame; | 71 int ms_per_frame; |
72 int tag; | 72 int tag; |
73 | 73 |
74 uint8_t *audio_fifo; | 74 uint8_t audio_fifo[AUDIO_FIFO_SIZE]; |
75 int audio_in_pos; | 75 int audio_in_pos; |
76 int audio_out_pos; | 76 int audio_out_pos; |
77 int audio_size; | 77 int audio_size; |
78 | 78 |
79 int video_type; | 79 int video_type; |
92 {CODEC_ID_MP3, 0x02}, | 92 {CODEC_ID_MP3, 0x02}, |
93 {CODEC_ID_PCM_S16LE, 0x03}, | 93 {CODEC_ID_PCM_S16LE, 0x03}, |
94 //{CODEC_ID_NELLYMOSER, 0x06}, | 94 //{CODEC_ID_NELLYMOSER, 0x06}, |
95 {0, 0}, | 95 {0, 0}, |
96 }; | 96 }; |
97 | |
98 static const int sSampleRates[3][4] = { | |
99 {44100, 48000, 32000, 0}, | |
100 {22050, 24000, 16000, 0}, | |
101 {11025, 12000, 8000, 0}, | |
102 }; | |
103 | |
104 static const int sBitRates[2][3][15] = { | |
105 { { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448}, | |
106 { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384}, | |
107 { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320} | |
108 }, | |
109 { { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256}, | |
110 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}, | |
111 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160} | |
112 }, | |
113 }; | |
114 | |
115 static const int sSamplesPerFrame[3][3] = | |
116 { | |
117 { 384, 1152, 1152 }, | |
118 { 384, 1152, 576 }, | |
119 { 384, 1152, 576 } | |
120 }; | |
121 | |
122 static const int sBitsPerSlot[3] = { | |
123 32, | |
124 8, | |
125 8 | |
126 }; | |
127 | |
128 static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono ) | |
129 { | |
130 uint32_t header = AV_RB32(data); | |
131 int layerID = 3 - ((header >> 17) & 0x03); | |
132 int bitRateID = ((header >> 12) & 0x0f); | |
133 int sampleRateID = ((header >> 10) & 0x03); | |
134 int bitRate = 0; | |
135 int bitsPerSlot = sBitsPerSlot[layerID]; | |
136 int isPadded = ((header >> 9) & 0x01); | |
137 | |
138 if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) { | |
139 return 0; | |
140 } | |
141 | |
142 *isMono = ((header >> 6) & 0x03) == 0x03; | |
143 | |
144 if ( (header >> 19 ) & 0x01 ) { | |
145 *sampleRate = sSampleRates[0][sampleRateID]; | |
146 bitRate = sBitRates[0][layerID][bitRateID] * 1000; | |
147 *samplesPerFrame = sSamplesPerFrame[0][layerID]; | |
148 } else { | |
149 if ( (header >> 20) & 0x01 ) { | |
150 *sampleRate = sSampleRates[1][sampleRateID]; | |
151 bitRate = sBitRates[1][layerID][bitRateID] * 1000; | |
152 *samplesPerFrame = sSamplesPerFrame[1][layerID]; | |
153 } else { | |
154 *sampleRate = sSampleRates[2][sampleRateID]; | |
155 bitRate = sBitRates[1][layerID][bitRateID] * 1000; | |
156 *samplesPerFrame = sSamplesPerFrame[2][layerID]; | |
157 } | |
158 } | |
159 | |
160 *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) ); | |
161 | |
162 return 1; | |
163 } | |
164 | 97 |
165 #ifdef CONFIG_MUXERS | 98 #ifdef CONFIG_MUXERS |
166 static void put_swf_tag(AVFormatContext *s, int tag) | 99 static void put_swf_tag(AVFormatContext *s, int tag) |
167 { | 100 { |
168 SWFContext *swf = s->priv_data; | 101 SWFContext *swf = s->priv_data; |
321 int i, width, height, rate, rate_base; | 254 int i, width, height, rate, rate_base; |
322 | 255 |
323 swf->audio_in_pos = 0; | 256 swf->audio_in_pos = 0; |
324 swf->audio_out_pos = 0; | 257 swf->audio_out_pos = 0; |
325 swf->audio_size = 0; | 258 swf->audio_size = 0; |
326 swf->audio_fifo = av_malloc(AUDIO_FIFO_SIZE); | |
327 swf->sound_samples = 0; | 259 swf->sound_samples = 0; |
328 swf->video_samples = 0; | 260 swf->video_samples = 0; |
329 swf->swf_frame_number = 0; | 261 swf->swf_frame_number = 0; |
330 swf->video_frame_number = 0; | 262 swf->video_frame_number = 0; |
331 | 263 |
332 video_enc = NULL; | 264 video_enc = NULL; |
333 audio_enc = NULL; | 265 audio_enc = NULL; |
334 for(i=0;i<s->nb_streams;i++) { | 266 for(i=0;i<s->nb_streams;i++) { |
335 enc = s->streams[i]->codec; | 267 enc = s->streams[i]->codec; |
336 if (enc->codec_type == CODEC_TYPE_AUDIO) | 268 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
337 audio_enc = enc; | 269 if (enc->codec_id == CODEC_ID_MP3) { |
338 else { | 270 if (!enc->frame_size) { |
271 av_log(s, AV_LOG_ERROR, "audio frame size not set\n"); | |
272 return -1; | |
273 } | |
274 audio_enc = enc; | |
275 } else { | |
276 av_log(enc, AV_LOG_ERROR, "SWF only supports MP3\n"); | |
277 return -1; | |
278 } | |
279 } else { | |
339 if ( enc->codec_id == CODEC_ID_VP6F || | 280 if ( enc->codec_id == CODEC_ID_VP6F || |
340 enc->codec_id == CODEC_ID_FLV1 || | 281 enc->codec_id == CODEC_ID_FLV1 || |
341 enc->codec_id == CODEC_ID_MJPEG ) { | 282 enc->codec_id == CODEC_ID_MJPEG ) { |
342 video_enc = enc; | 283 video_enc = enc; |
343 } else { | 284 } else { |
474 static int swf_write_video(AVFormatContext *s, | 415 static int swf_write_video(AVFormatContext *s, |
475 AVCodecContext *enc, const uint8_t *buf, int size) | 416 AVCodecContext *enc, const uint8_t *buf, int size) |
476 { | 417 { |
477 SWFContext *swf = s->priv_data; | 418 SWFContext *swf = s->priv_data; |
478 ByteIOContext *pb = &s->pb; | 419 ByteIOContext *pb = &s->pb; |
479 int c = 0; | |
480 int outSize = 0; | |
481 int outSamples = 0; | |
482 | 420 |
483 /* Flash Player limit */ | 421 /* Flash Player limit */ |
484 if ( swf->swf_frame_number == 16000 ) { | 422 if ( swf->swf_frame_number == 16000 ) { |
485 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); | 423 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); |
486 } | |
487 | |
488 if ( swf->audio_type ) { | |
489 /* Prescan audio data for this swf frame */ | |
490 retry_swf_audio_packet: | |
491 if ( ( swf->audio_size-outSize ) >= 4 ) { | |
492 int mp3FrameSize = 0; | |
493 int mp3SampleRate = 0; | |
494 int mp3IsMono = 0; | |
495 int mp3SamplesPerFrame = 0; | |
496 | |
497 /* copy out mp3 header from ring buffer */ | |
498 uint8_t header[4]; | |
499 for (c=0; c<4; c++) { | |
500 header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE]; | |
501 } | |
502 | |
503 if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) { | |
504 if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) { | |
505 outSize += mp3FrameSize; | |
506 outSamples += mp3SamplesPerFrame; | |
507 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) { | |
508 goto retry_swf_audio_packet; | |
509 } | |
510 } | |
511 } else { | |
512 /* invalid mp3 data, skip forward | |
513 we need to do this since the Flash Player | |
514 does not like custom headers */ | |
515 swf->audio_in_pos ++; | |
516 swf->audio_size --; | |
517 swf->audio_in_pos %= AUDIO_FIFO_SIZE; | |
518 goto retry_swf_audio_packet; | |
519 } | |
520 } | |
521 | |
522 /* audio stream is behind video stream, bail */ | |
523 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) { | |
524 return 0; | |
525 } | |
526 } | 424 } |
527 | 425 |
528 if ( swf->video_type == CODEC_ID_VP6F || | 426 if ( swf->video_type == CODEC_ID_VP6F || |
529 swf->video_type == CODEC_ID_FLV1 ) { | 427 swf->video_type == CODEC_ID_FLV1 ) { |
530 if ( swf->video_frame_number == 0 ) { | 428 if ( swf->video_frame_number == 0 ) { |
609 swf->swf_frame_number ++; | 507 swf->swf_frame_number ++; |
610 | 508 |
611 swf->video_samples += swf->samples_per_frame; | 509 swf->video_samples += swf->samples_per_frame; |
612 | 510 |
613 /* streaming sound always should be placed just before showframe tags */ | 511 /* streaming sound always should be placed just before showframe tags */ |
614 if ( outSize > 0 ) { | 512 if (swf->audio_type && swf->audio_in_pos) { |
615 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG); | 513 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG); |
616 put_le16(pb, outSamples); | 514 put_le16(pb, swf->sound_samples); |
617 put_le16(pb, 0); | 515 put_le16(pb, 0); // seek samples |
618 for (c=0; c<outSize; c++) { | 516 put_buffer(pb, swf->audio_fifo, swf->audio_in_pos); |
619 put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]); | |
620 } | |
621 put_swf_end_tag(s); | 517 put_swf_end_tag(s); |
622 | 518 |
623 /* update FIFO */ | 519 /* update FIFO */ |
624 swf->sound_samples += outSamples; | 520 swf->sound_samples = 0; |
625 swf->audio_in_pos += outSize; | 521 swf->audio_in_pos = 0; |
626 swf->audio_size -= outSize; | |
627 swf->audio_in_pos %= AUDIO_FIFO_SIZE; | |
628 } | 522 } |
629 | 523 |
630 /* output the frame */ | 524 /* output the frame */ |
631 put_swf_tag(s, TAG_SHOWFRAME); | 525 put_swf_tag(s, TAG_SHOWFRAME); |
632 put_swf_end_tag(s); | 526 put_swf_end_tag(s); |
638 | 532 |
639 static int swf_write_audio(AVFormatContext *s, | 533 static int swf_write_audio(AVFormatContext *s, |
640 AVCodecContext *enc, const uint8_t *buf, int size) | 534 AVCodecContext *enc, const uint8_t *buf, int size) |
641 { | 535 { |
642 SWFContext *swf = s->priv_data; | 536 SWFContext *swf = s->priv_data; |
643 int c = 0; | |
644 | 537 |
645 /* Flash Player limit */ | 538 /* Flash Player limit */ |
646 if ( swf->swf_frame_number == 16000 ) { | 539 if ( swf->swf_frame_number == 16000 ) { |
647 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); | 540 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); |
648 } | 541 } |
649 | 542 |
650 if (enc->codec_id == CODEC_ID_MP3 ) { | 543 if (swf->audio_in_pos + size >= AUDIO_FIFO_SIZE) { |
651 for (c=0; c<size; c++) { | 544 av_log(s, AV_LOG_ERROR, "audio fifo too small to mux audio essence\n"); |
652 swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c]; | 545 return -1; |
653 } | 546 } |
654 swf->audio_size += size; | 547 |
655 swf->audio_out_pos += size; | 548 memcpy(swf->audio_fifo + swf->audio_in_pos, buf, size); |
656 swf->audio_out_pos %= AUDIO_FIFO_SIZE; | 549 swf->audio_in_pos += size; |
657 } | 550 swf->sound_samples += enc->frame_size; |
658 | 551 |
659 /* if audio only stream make sure we add swf frames */ | 552 /* if audio only stream make sure we add swf frames */ |
660 if ( swf->video_type == 0 ) { | 553 if ( swf->video_type == 0 ) { |
661 swf_write_video(s, enc, 0, 0); | 554 swf_write_video(s, enc, 0, 0); |
662 } | 555 } |
699 put_le32(pb, file_size); | 592 put_le32(pb, file_size); |
700 url_fseek(pb, swf->duration_pos, SEEK_SET); | 593 url_fseek(pb, swf->duration_pos, SEEK_SET); |
701 put_le16(pb, video_enc->frame_number); | 594 put_le16(pb, video_enc->frame_number); |
702 url_fseek(pb, file_size, SEEK_SET); | 595 url_fseek(pb, file_size, SEEK_SET); |
703 } | 596 } |
704 | |
705 av_free(swf->audio_fifo); | |
706 | |
707 return 0; | 597 return 0; |
708 } | 598 } |
709 #endif //CONFIG_MUXERS | 599 #endif //CONFIG_MUXERS |
710 | 600 |
711 /*********************************************/ | 601 /*********************************************/ |