..首页..站长介绍..手绘作品..生活日记..过客留言..友情链拉..我的照片..
Category
 生活点滴
Infomation
共有日志:166
评论:15
注册观员:90
Search
首页-->工作学习-->关于多媒体文件处理

swf.c
--------------------------------------------------------------------------------------------------
00001 /*00002  * Flash Compatible Streaming Format00003  * Copyright (c) 2000 Fabrice Bellard.00004  * Copyright (c) 2003 Tinic Uro.00005  *00006  * This library is free software; you can redistribute it and/or00007  * modify it under the terms of the GNU Lesser General Public00008  * License as published by the Free Software Foundation; either00009  * version 2 of the License, or (at your option) any later version.00010  *00011  * This library is distributed in the hope that it will be useful,00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU00014  * Lesser General Public License for more details.00015  *00016  * You should have received a copy of the GNU Lesser General Public00017  * License along with this library; if not, write to the Free Software00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA00019  */00020 #include "avformat.h"00021 #include "bitstream.h"00022 00023 /* should have a generic way to indicate probable size */00024 #define DUMMY_FILE_SIZE   (100 * 1024 * 1024)00025 #define DUMMY_DURATION    600 /* in seconds */00026 00027 #define TAG_END           000028 #define TAG_SHOWFRAME     100029 #define TAG_DEFINESHAPE   200030 #define TAG_FREECHARACTER 300031 #define TAG_PLACEOBJECT   400032 #define TAG_REMOVEOBJECT  500033 #define TAG_STREAMHEAD    1800034 #define TAG_STREAMBLOCK   1900035 #define TAG_JPEG2         2100036 #define TAG_PLACEOBJECT2  2600037 #define TAG_STREAMHEAD2   4500038 #define TAG_VIDEOSTREAM   6000039 #define TAG_VIDEOFRAME    6100040 00041 #define TAG_LONG         0x10000042 00043 /* flags for shape definition */00044 #define FLAG_MOVETO      0x0100045 #define FLAG_SETFILL0    0x0200046 #define FLAG_SETFILL1    0x0400047 00048 #define SWF_VIDEO_CODEC_FLV1    0x0200049 00050 #define AUDIO_FIFO_SIZE 6553600051 00052 /* character id used */00053 #define BITMAP_ID 000054 #define VIDEO_ID 000055 #define SHAPE_ID  100056 00057 #undef NDEBUG00058 #include <assert.h>00059 00060 typedef struct {00061 00062     offset_t duration_pos;00063     offset_t tag_pos;00064     00065     int samples_per_frame;00066     int sound_samples;00067     int video_samples;00068     int swf_frame_number;00069     int video_frame_number;00070     int ms_per_frame;00071     int ch_id;00072     int tag;00073 00074     uint8_t *audio_fifo;00075     int audio_in_pos;00076     int audio_out_pos;00077     int audio_size;00078 00079     int video_type;00080     int audio_type;00081 } SWFContext;00082 00083 static const int sSampleRates[3][4] = {00084     {44100, 48000, 32000, 0},00085     {22050, 24000, 16000, 0},00086     {11025, 12000,  8000, 0},00087 };00088 00089 static const int sBitRates[2][3][15] = {00090     {   {  0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448},00091         {  0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384},00092         {  0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320}00093     },00094     {   {  0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256},00095         {  0,  8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160},00096         {  0,  8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}00097     },00098 };00099 00100 static const int sSamplesPerFrame[3][3] =00101 {00102     {  384,     1152,    1152 },00103     {  384,     1152,     576 },00104     {  384,     1152,     576 }00105 };00106 00107 static const int sBitsPerSlot[3] = {00108     32,00109     8,00110     800111 };00112 00113 static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono )00114 {00115     uint8_t *dataTmp = (uint8_t *)data;00116     uint32_t header = ( (uint32_t)dataTmp[0] << 24 ) | ( (uint32_t)dataTmp[1] << 16 ) | ( (uint32_t)dataTmp[2] << 8 ) | (uint32_t)dataTmp[3];00117     int layerID = 3 - ((header >> 17) & 0x03);00118     int bitRateID = ((header >> 12) & 0x0f);00119     int sampleRateID = ((header >> 10) & 0x03);00120     int bitRate = 0;00121     int bitsPerSlot = sBitsPerSlot[layerID];00122     int isPadded = ((header >> 9) & 0x01);00123     00124     if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {00125         return 0;00126     }00127 00128     *isMono = ((header >>  6) & 0x03) == 0x03;00129 00130     if ( (header >> 19 ) & 0x01 ) {00131         *sampleRate = sSampleRates[0][sampleRateID];00132         bitRate = sBitRates[0][layerID][bitRateID] * 1000;00133         *samplesPerFrame = sSamplesPerFrame[0][layerID];00134     } else {00135         if ( (header >> 20) & 0x01 ) {00136             *sampleRate = sSampleRates[1][sampleRateID];00137             bitRate = sBitRates[1][layerID][bitRateID] * 1000;00138             *samplesPerFrame = sSamplesPerFrame[1][layerID];00139         } else {00140             *sampleRate = sSampleRates[2][sampleRateID];00141             bitRate = sBitRates[1][layerID][bitRateID] * 1000;00142             *samplesPerFrame = sSamplesPerFrame[2][layerID];00143         }00144     }00145 00146     *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );00147 00148     return 1;00149 }00150 00151 #ifdef CONFIG_ENCODERS00152 static void put_swf_tag(AVFormatContext *s, int tag)00153 {00154     SWFContext *swf = s->priv_data;00155     ByteIOContext *pb = &s->pb;00156 00157     swf->tag_pos = url_ftell(pb);00158     swf->tag = tag;00159     /* reserve some room for the tag */00160     if (tag & TAG_LONG) {00161         put_le16(pb, 0);00162         put_le32(pb, 0);00163     } else {00164         put_le16(pb, 0);00165     }00166 }00167 00168 static void put_swf_end_tag(AVFormatContext *s)00169 {00170     SWFContext *swf = s->priv_data;00171     ByteIOContext *pb = &s->pb;00172     offset_t pos;00173     int tag_len, tag;00174 00175     pos = url_ftell(pb);00176     tag_len = pos - swf->tag_pos - 2;00177     tag = swf->tag;00178     url_fseek(pb, swf->tag_pos, SEEK_SET);00179     if (tag & TAG_LONG) {00180         tag &= ~TAG_LONG;00181         put_le16(pb, (tag << 6) | 0x3f);00182         put_le32(pb, tag_len - 4);00183     } else {00184         assert(tag_len < 0x3f);00185         put_le16(pb, (tag << 6) | tag_len);00186     }00187     url_fseek(pb, pos, SEEK_SET);00188 }00189 00190 static inline void max_nbits(int *nbits_ptr, int val)00191 {00192     int n;00193 00194     if (val == 0)00195         return;00196     val = abs(val);00197     n = 1;00198     while (val != 0) {00199         n++;00200         val >>= 1;00201     }00202     if (n > *nbits_ptr)00203         *nbits_ptr = n;00204 }00205 00206 static void put_swf_rect(ByteIOContext *pb, 00207                          int xmin, int xmax, int ymin, int ymax)00208 {00209     PutBitContext p;00210     uint8_t buf[256];00211     int nbits, mask;00212 00213     init_put_bits(&p, buf, sizeof(buf));00214     00215     nbits = 0;00216     max_nbits(&nbits, xmin);00217     max_nbits(&nbits, xmax);00218     max_nbits(&nbits, ymin);00219     max_nbits(&nbits, ymax);00220     mask = (1 << nbits) - 1;00221 00222     /* rectangle info */00223     put_bits(&p, 5, nbits);00224     put_bits(&p, nbits, xmin & mask);00225     put_bits(&p, nbits, xmax & mask);00226     put_bits(&p, nbits, ymin & mask);00227     put_bits(&p, nbits, ymax & mask);00228     00229     flush_put_bits(&p);00230     put_buffer(pb, buf, pbBufPtr(&p) - p.buf);00231 }00232 00233 static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)00234 {00235     int nbits, mask;00236 00237     put_bits(pb, 1, 1); /* edge */00238     put_bits(pb, 1, 1); /* line select */00239     nbits = 2;00240     max_nbits(&nbits, dx);00241     max_nbits(&nbits, dy);00242 00243     mask = (1 << nbits) - 1;00244     put_bits(pb, 4, nbits - 2); /* 16 bits precision */00245     if (dx == 0) {00246       put_bits(pb, 1, 0); 00247       put_bits(pb, 1, 1); 00248       put_bits(pb, nbits, dy & mask);00249     } else if (dy == 0) {00250       put_bits(pb, 1, 0); 00251       put_bits(pb, 1, 0); 00252       put_bits(pb, nbits, dx & mask);00253     } else {00254       put_bits(pb, 1, 1); 00255       put_bits(pb, nbits, dx & mask);00256       put_bits(pb, nbits, dy & mask);00257     }00258 }00259 00260 #define FRAC_BITS 1600261 00262 /* put matrix */00263 static void put_swf_matrix(ByteIOContext *pb,00264                            int a, int b, int c, int d, int tx, int ty)00265 {00266     PutBitContext p;00267     uint8_t buf[256];00268     int nbits;00269 00270     init_put_bits(&p, buf, sizeof(buf));00271     00272     put_bits(&p, 1, 1); /* a, d present */00273     nbits = 1;00274     max_nbits(&nbits, a);00275     max_nbits(&nbits, d);00276     put_bits(&p, 5, nbits); /* nb bits */00277     put_bits(&p, nbits, a);00278     put_bits(&p, nbits, d);00279     00280     put_bits(&p, 1, 1); /* b, c present */00281     nbits = 1;00282     max_nbits(&nbits, c);00283     max_nbits(&nbits, b);00284     put_bits(&p, 5, nbits); /* nb bits */00285     put_bits(&p, nbits, c);00286     put_bits(&p, nbits, b);00287 00288     nbits = 1;00289     max_nbits(&nbits, tx);00290     max_nbits(&nbits, ty);00291     put_bits(&p, 5, nbits); /* nb bits */00292     put_bits(&p, nbits, tx);00293     put_bits(&p, nbits, ty);00294 00295     flush_put_bits(&p);00296     put_buffer(pb, buf, pbBufPtr(&p) - p.buf);00297 }00298 00299 /* */00300 static int swf_write_header(AVFormatContext *s)00301 {00302     SWFContext *swf;00303     ByteIOContext *pb = &s->pb;00304     AVCodecContext *enc, *audio_enc, *video_enc;00305     PutBitContext p;00306     uint8_t buf1[256];00307     int i, width, height, rate, rate_base;00308 00309     swf = av_malloc(sizeof(SWFContext));00310     if (!swf)00311         return -1;00312     s->priv_data = swf;00313 00314     swf->ch_id = -1;00315     swf->audio_in_pos = 0;00316     swf->audio_out_pos = 0;00317     swf->audio_size = 0;00318     swf->audio_fifo = av_malloc(AUDIO_FIFO_SIZE);00319     swf->sound_samples = 0;00320     swf->video_samples = 0;00321     swf->swf_frame_number = 0;00322     swf->video_frame_number = 0;00323 00324     video_enc = NULL;00325     audio_enc = NULL;00326     for(i=0;i<s->nb_streams;i++) {00327         enc = s->streams[i]->codec;00328         if (enc->codec_type == CODEC_TYPE_AUDIO)00329             audio_enc = enc;00330         else {00331             if ( enc->codec_id == CODEC_ID_FLV1 || enc->codec_id == CODEC_ID_MJPEG ) {00332                 video_enc = enc;00333             } else {00334                 av_log(enc, AV_LOG_ERROR, "SWF only supports FLV1 and MJPEG\n");00335                 return -1;00336             }00337         }00338     }00339 00340     if (!video_enc) {00341         /* currenty, cannot work correctly if audio only */00342         swf->video_type = 0;00343         width = 320;00344         height = 200;00345         rate = 10;00346         rate_base= 1;00347     } else {00348         swf->video_type = video_enc->codec_id;00349         width = video_enc->width;00350         height = video_enc->height;00351         rate = video_enc->time_base.den;00352         rate_base = video_enc->time_base.num;00353     }00354 00355     if (!audio_enc ) {00356         swf->audio_type = 0;00357         swf->samples_per_frame = ( 44100. * rate_base ) / rate;00358     } else {00359         swf->audio_type = audio_enc->codec_id;00360         swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;00361     }00362 00363     put_tag(pb, "FWS");00364     if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {00365         put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */00366     } else {00367         put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */00368     }00369     put_le32(pb, DUMMY_FILE_SIZE); /* dummy size 00370                                       (will be patched if not streamed) */ 00371 00372     put_swf_rect(pb, 0, width * 20, 0, height * 20);00373     put_le16(pb, (rate * 256) / rate_base); /* frame rate */00374     swf->duration_pos = url_ftell(pb);00375     put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */00376     00377     /* define a shape with the jpeg inside */00378     if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {00379     } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) {00380         put_swf_tag(s, TAG_DEFINESHAPE);00381 00382         put_le16(pb, SHAPE_ID); /* ID of shape */00383         /* bounding rectangle */00384         put_swf_rect(pb, 0, width, 0, height);00385         /* style info */00386         put_byte(pb, 1); /* one fill style */00387         put_byte(pb, 0x41); /* clipped bitmap fill */00388         put_le16(pb, BITMAP_ID); /* bitmap ID */00389         /* position of the bitmap */00390         put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0, 00391                         0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);00392         put_byte(pb, 0); /* no line style */00393     00394         /* shape drawing */00395         init_put_bits(&p, buf1, sizeof(buf1));00396         put_bits(&p, 4, 1); /* one fill bit */00397         put_bits(&p, 4, 0); /* zero line bit */00398      00399         put_bits(&p, 1, 0); /* not an edge */00400         put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);00401         put_bits(&p, 5, 1); /* nbits */00402         put_bits(&p, 1, 0); /* X */00403         put_bits(&p, 1, 0); /* Y */00404         put_bits(&p, 1, 1); /* set fill style 1 */00405     00406         /* draw the rectangle ! */00407         put_swf_line_edge(&p, width, 0);00408         put_swf_line_edge(&p, 0, height);00409         put_swf_line_edge(&p, -width, 0);00410         put_swf_line_edge(&p, 0, -height);00411     00412         /* end of shape */00413         put_bits(&p, 1, 0); /* not an edge */00414         put_bits(&p, 5, 0);00415 00416         flush_put_bits(&p);00417         put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);00418 00419         put_swf_end_tag(s);00420     }00421     00422     if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {00423         int v;00424 00425         /* start sound */00426         put_swf_tag(s, TAG_STREAMHEAD2);00427 00428         v = 0;00429         switch(audio_enc->sample_rate) {00430         case 11025:00431             v |= 1 << 2;00432             break;00433         case 22050:00434             v |= 2 << 2;00435             break;00436         case 44100:00437             v |= 3 << 2;00438             break;00439         default:00440             /* not supported */00441             av_free(swf->audio_fifo);00442             av_free(swf);00443             return -1;00444         }00445         v |= 0x02; /* 16 bit playback */00446         if (audio_enc->channels == 2)00447             v |= 0x01; /* stereo playback */00448         put_byte(&s->pb, v);00449         v |= 0x20; /* mp3 compressed */00450         put_byte(&s->pb, v);00451         put_le16(&s->pb, swf->samples_per_frame);  /* avg samples per frame */00452         put_le16(&s->pb, 0);00453         00454         put_swf_end_tag(s);00455     }00456 00457     put_flush_packet(&s->pb);00458     return 0;00459 }00460 00461 static int swf_write_video(AVFormatContext *s, 00462                            AVCodecContext *enc, const uint8_t *buf, int size)00463 {00464     SWFContext *swf = s->priv_data;00465     ByteIOContext *pb = &s->pb;00466     int c = 0;00467     int outSize = 0;00468     int outSamples = 0;00469     00470     /* Flash Player limit */00471     if ( swf->swf_frame_number == 16000 ) {00472         av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");00473     }00474 00475     if ( swf->audio_type ) {00476         /* Prescan audio data for this swf frame */00477 retry_swf_audio_packet:00478         if ( ( swf->audio_size-outSize ) >= 4 ) {00479             int mp3FrameSize = 0;00480             int mp3SampleRate = 0;00481             int mp3IsMono = 0;00482             int mp3SamplesPerFrame = 0;00483             00484             /* copy out mp3 header from ring buffer */00485             uint8_t header[4];00486             for (c=0; c<4; c++) {00487                 header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE];00488             }00489             00490             if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) {00491                 if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) {00492                     outSize += mp3FrameSize;00493                     outSamples += mp3SamplesPerFrame;00494                     if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {00495                         goto retry_swf_audio_packet;00496                     }00497                 }00498             } else {00499                 /* invalid mp3 data, skip forward00500                 we need to do this since the Flash Player 00501                 does not like custom headers */00502                 swf->audio_in_pos ++;00503                 swf->audio_size --;00504                 swf->audio_in_pos %= AUDIO_FIFO_SIZE;00505                 goto retry_swf_audio_packet;00506             }00507         }00508         00509         /* audio stream is behind video stream, bail */00510         if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {00511             return 0;00512         }00513     }00514 00515             if ( swf->video_type == CODEC_ID_FLV1 ) {00516                 if ( swf->video_frame_number == 0 ) {00517                     /* create a new video object */00518                     put_swf_tag(s, TAG_VIDEOSTREAM);00519                     put_le16(pb, VIDEO_ID);00520                     put_le16(pb, 15000 ); /* hard flash player limit */00521                     put_le16(pb, enc->width);00522                     put_le16(pb, enc->height);00523                     put_byte(pb, 0);00524                     put_byte(pb, SWF_VIDEO_CODEC_FLV1);00525                     put_swf_end_tag(s);00526                     00527                     /* place the video object for the first time */00528                     put_swf_tag(s, TAG_PLACEOBJECT2);00529                     put_byte(pb, 0x36);00530                     put_le16(pb, 1);00531                     put_le16(pb, VIDEO_ID);00532                     put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);00533                     put_le16(pb, swf->video_frame_number );00534                     put_byte(pb, 'v');00535                     put_byte(pb, 'i');00536                     put_byte(pb, 'd');00537                     put_byte(pb, 'e');00538                     put_byte(pb, 'o');00539                     put_byte(pb, 0x00);00540                     put_swf_end_tag(s);00541                 } else {00542                     /* mark the character for update */00543                     put_swf_tag(s, TAG_PLACEOBJECT2);00544                     put_byte(pb, 0x11);00545                     put_le16(pb, 1);00546                     put_le16(pb, swf->video_frame_number );00547                     put_swf_end_tag(s);00548                 }00549     00550                     /* set video frame data */00551                     put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);00552                     put_le16(pb, VIDEO_ID); 00553                     put_le16(pb, swf->video_frame_number++ );00554                     put_buffer(pb, buf, size);00555                     put_swf_end_tag(s);00556             } else if ( swf->video_type == CODEC_ID_MJPEG ) {00557                 if (swf->swf_frame_number > 0) {00558                     /* remove the shape */00559                     put_swf_tag(s, TAG_REMOVEOBJECT);00560                     put_le16(pb, SHAPE_ID); /* shape ID */00561                     put_le16(pb, 1); /* depth */00562                     put_swf_end_tag(s);00563                 00564                     /* free the bitmap */00565                     put_swf_tag(s, TAG_FREECHARACTER);00566                     put_le16(pb, BITMAP_ID);00567                     put_swf_end_tag(s);00568                 }00569         00570                 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);00571         00572                 put_le16(pb, BITMAP_ID); /* ID of the image */00573         00574                 /* a dummy jpeg header seems to be required */00575                 put_byte(pb, 0xff); 00576                 put_byte(pb, 0xd8);00577                 put_byte(pb, 0xff);00578                 put_byte(pb, 0xd9);00579                 /* write the jpeg image */00580                 put_buffer(pb, buf, size);00581         00582                 put_swf_end_tag(s);00583         00584                 /* draw the shape */00585         00586                 put_swf_tag(s, TAG_PLACEOBJECT);00587                 put_le16(pb, SHAPE_ID); /* shape ID */00588                 put_le16(pb, 1); /* depth */00589                 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);00590                 put_swf_end_tag(s);00591             } else {00592                 /* invalid codec */00593             }00594     00595             swf->swf_frame_number ++;00596 00597     swf->video_samples += swf->samples_per_frame;00598 00599     /* streaming sound always should be placed just before showframe tags */00600     if ( outSize > 0 ) {00601         put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);00602         put_le16(pb, outSamples);00603         put_le16(pb, 0);00604         for (c=0; c<outSize; c++) {00605             put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);00606         }00607         put_swf_end_tag(s);00608     00609         /* update FIFO */00610         swf->sound_samples += outSamples;00611         swf->audio_in_pos += outSize;00612         swf->audio_size -= outSize;00613         swf->audio_in_pos %= AUDIO_FIFO_SIZE;00614     }00615 00616     /* output the frame */00617     put_swf_tag(s, TAG_SHOWFRAME);00618     put_swf_end_tag(s);00619     00620     put_flush_packet(&s->pb);00621     00622     return 0;00623 }00624 00625 static int swf_write_audio(AVFormatContext *s, 00626                            AVCodecContext *enc, const uint8_t *buf, int size)00627 {00628     SWFContext *swf = s->priv_data;00629     int c = 0;00630 00631     /* Flash Player limit */00632     if ( swf->swf_frame_number == 16000 ) {00633         av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");00634     }00635 00636     if (enc->codec_id == CODEC_ID_MP3 ) {00637         for (c=0; c<size; c++) {00638             swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c];00639         }00640         swf->audio_size += size;00641         swf->audio_out_pos += size;00642         swf->audio_out_pos %= AUDIO_FIFO_SIZE;00643     }00644 00645     /* if audio only stream make sure we add swf frames */00646     if ( swf->video_type == 0 ) {00647         swf_write_video(s, enc, 0, 0);00648     }00649 00650     return 0;00651 }00652 00653 static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)00654 {00655     AVCodecContext *codec = s->streams[pkt->stream_index]->codec;00656     if (codec->codec_type == CODEC_TYPE_AUDIO)00657         return swf_write_audio(s, codec, pkt->data, pkt->size);00658     else00659         return swf_write_video(s, codec, pkt->data, pkt->size);00660 }00661 00662 static int swf_write_trailer(AVFormatContext *s)00663 {00664     SWFContext *swf = s->priv_data;00665     ByteIOContext *pb = &s->pb;00666     AVCodecContext *enc, *video_enc;00667     int file_size, i;00668 00669     video_enc = NULL;00670     for(i=0;i<s->nb_streams;i++) {00671         enc = s->streams[i]->codec;00672         if (enc->codec_type == CODEC_TYPE_VIDEO)00673             video_enc = enc;00674     }00675 00676     put_swf_tag(s, TAG_END);00677     put_swf_end_tag(s);00678     00679     put_flush_packet(&s->pb);00680 00681     /* patch file size and number of frames if not streamed */00682     if (!url_is_streamed(&s->pb) && video_enc) {00683         file_size = url_ftell(pb);00684         url_fseek(pb, 4, SEEK_SET);00685         put_le32(pb, file_size);00686         url_fseek(pb, swf->duration_pos, SEEK_SET);00687         put_le16(pb, video_enc->frame_number);00688     }00689     00690     av_free(swf->audio_fifo);00691 00692     return 0;00693 }00694 #endif //CONFIG_ENCODERS00695 00696 /*********************************************/00697 /* Extract FLV encoded frame and MP3 from swf00698    Note that the detection of the real frame00699    is inaccurate at this point as it can be00700    quite tricky to determine, you almost certainly 00701    will get a bad audio/video sync */00702 00703 static int get_swf_tag(ByteIOContext *pb, int *len_ptr)00704 {00705     int tag, len;00706     00707     if (url_feof(pb))00708         return -1;00709 00710     tag = get_le16(pb);00711     len = tag & 0x3f;00712     tag = tag >> 6;00713     if (len == 0x3f) {00714         len = get_le32(pb);00715     }00716 //    av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);00717     *len_ptr = len;00718     return tag;00719 }00720 00721 00722 static int swf_probe(AVProbeData *p)00723 {00724     /* check file header */00725     if (p->buf_size <= 16)00726         return 0;00727     if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&00728         p->buf[2] == 'S')00729         return AVPROBE_SCORE_MAX;00730     else00731         return 0;00732 }00733 00734 static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)00735 {00736     SWFContext *swf = 0;00737     ByteIOContext *pb = &s->pb;00738     int nbits, len, frame_rate, tag, v;00739     offset_t firstTagOff;00740     AVStream *ast = 0;00741     AVStream *vst = 0;00742 00743     swf = av_malloc(sizeof(SWFContext));00744     if (!swf)00745         return -1;00746     s->priv_data = swf;00747 00748     tag = get_be32(pb) & 0xffffff00;00749 00750     if (tag == MKBETAG('C', 'W', 'S', 0))00751     {00752         av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");00753         return AVERROR_IO;00754     }00755     if (tag != MKBETAG('F', 'W', 'S', 0))00756         return AVERROR_IO;00757     get_le32(pb);00758     /* skip rectangle size */00759     nbits = get_byte(pb) >> 3;00760     len = (4 * nbits - 3 + 7) / 8;00761     url_fskip(pb, len);00762     frame_rate = get_le16(pb);00763     get_le16(pb); /* frame count */00764     00765     /* The Flash Player converts 8.8 frame rates 00766        to milliseconds internally. Do the same to get 00767        a correct framerate */00768     swf->ms_per_frame = ( 1000 * 256 ) / frame_rate;00769     swf->samples_per_frame = 0;00770     swf->ch_id = -1;00771 00772     firstTagOff = url_ftell(pb);00773     for(;;) {00774         tag = get_swf_tag(pb, &len);00775         if (tag < 0) {00776             if ( ast || vst ) {00777                 if ( vst && ast ) {00778                     vst->codec->time_base.den = ast->codec->sample_rate / swf->samples_per_frame;00779                     vst->codec->time_base.num = 1;00780                 }00781                 break;00782             }00783             av_log(s, AV_LOG_ERROR, "No media found in SWF\n");00784             return AVERROR_IO;00785         }00786         if ( tag == TAG_VIDEOSTREAM && !vst) {00787             swf->ch_id = get_le16(pb);00788             get_le16(pb);00789             get_le16(pb);00790             get_le16(pb);00791             get_byte(pb);00792             /* Check for FLV1 */00793             if ( get_byte(pb) == SWF_VIDEO_CODEC_FLV1 ) {00794                 vst = av_new_stream(s, 0);00795                 av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */00796     00797                 vst->codec->codec_type = CODEC_TYPE_VIDEO;00798                 vst->codec->codec_id = CODEC_ID_FLV1;00799                 if ( swf->samples_per_frame ) {00800                     vst->codec->time_base.den = 1000. / swf->ms_per_frame;00801                     vst->codec->time_base.num = 1;00802                 }00803             }00804         } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {00805             /* streaming found */00806             get_byte(pb);00807             v = get_byte(pb);00808             swf->samples_per_frame = get_le16(pb);00809             if (len!=4)00810                 url_fskip(pb,len-4);00811             /* if mp3 streaming found, OK */00812             if ((v & 0x20) != 0) {00813                 if ( tag == TAG_STREAMHEAD2 ) {00814                     get_le16(pb);00815                 }00816                 ast = av_new_stream(s, 1);00817                 av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */00818                 if (!ast)00819                     return -ENOMEM;00820 00821                 if (v & 0x01)00822                     ast->codec->channels = 2;00823                 else00824                     ast->codec->channels = 1;00825 00826                 switch((v>> 2) & 0x03) {00827                 case 1:00828                     ast->codec->sample_rate = 11025;00829                     break;00830                 case 2:00831                     ast->codec->sample_rate = 22050;00832                     break;00833                 case 3:00834                     ast->codec->sample_rate = 44100;00835                     break;00836                 default:00837                     av_free(ast);00838                     return AVERROR_IO;00839                 }00840                 ast->codec->codec_type = CODEC_TYPE_AUDIO;00841                 ast->codec->codec_id = CODEC_ID_MP3;00842             }00843         } else {00844             url_fskip(pb, len);00845         }00846     }00847     url_fseek(pb, firstTagOff, SEEK_SET);00848     00849     return 0;00850 }00851 00852 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)00853 {00854     SWFContext *swf = s->priv_data;00855     ByteIOContext *pb = &s->pb;00856     AVStream *st = 0;00857     int tag, len, i, frame;00858     00859     for(;;) {00860         tag = get_swf_tag(pb, &len);00861         if (tag < 0) 00862             return AVERROR_IO;00863         if (tag == TAG_VIDEOFRAME) {00864             for( i=0; i<s->nb_streams; i++ ) {00865                 st = s->streams[i];00866                 if (st->id == 0) {00867                     if ( get_le16(pb) == swf->ch_id ) {00868                         frame = get_le16(pb);00869                         av_get_packet(pb, pkt, len-4);00870                         pkt->pts = frame * swf->ms_per_frame;00871                         pkt->stream_index = st->index;00872                         return pkt->size;00873                     } else {00874                         url_fskip(pb, len-2);00875                         continue;00876                     }00877                 }00878             }    00879             url_fskip(pb, len);00880         } else if (tag == TAG_STREAMBLOCK) {00881             for( i=0; i<s->nb_streams; i++ ) {00882                 st = s->streams[i];00883                 if (st->id == 1) {00884                     av_get_packet(pb, pkt, len);00885                     pkt->stream_index = st->index;00886                     return pkt->size;00887                 }00888             }00889             url_fskip(pb, len);00890         } else {00891             url_fskip(pb, len);00892         }00893     }00894     return 0;00895 }00896 00897 static int swf_read_close(AVFormatContext *s)00898 {00899      return 0;00900 }00901 00902 static AVInputFormat swf_iformat = {00903     "swf",00904     "Flash format",00905     sizeof(SWFContext),00906     swf_probe,00907     swf_read_header,00908     swf_read_packet,00909     swf_read_close,00910 };00911 00912 #ifdef CONFIG_ENCODERS00913 static AVOutputFormat swf_oformat = {00914     "swf",00915     "Flash format",00916     "application/x-shockwave-flash",00917     "swf",00918     sizeof(SWFContext),00919     CODEC_ID_MP3,00920     CODEC_ID_FLV1,00921     swf_write_header,00922     swf_write_packet,00923     swf_write_trailer,00924 };00925 #endif //CONFIG_ENCODERS00926 00927 int swf_init(void)00928 {00929     av_register_input_format(&swf_iformat);00930 #ifdef CONFIG_ENCODERS00931     av_register_output_format(&swf_oformat);00932 #endif //CONFIG_ENCODERS00933     return 0;00934 }