LCOV - code coverage report
Current view: top level - libavformat - swfenc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 179 312 57.4 %
Date: 2017-12-18 20:14:19 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /*
       2             :  * Flash Compatible Streaming Format muxer
       3             :  * Copyright (c) 2000 Fabrice Bellard
       4             :  * Copyright (c) 2003 Tinic Uro
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : #include "libavcodec/put_bits.h"
      24             : #include "libavutil/avassert.h"
      25             : #include "avformat.h"
      26             : #include "swf.h"
      27             : 
      28          77 : static void put_swf_tag(AVFormatContext *s, int tag)
      29             : {
      30          77 :     SWFContext *swf = s->priv_data;
      31          77 :     AVIOContext *pb = s->pb;
      32             : 
      33          77 :     swf->tag_pos = avio_tell(pb);
      34          77 :     swf->tag = tag;
      35             :     /* reserve some room for the tag */
      36          77 :     if (tag & TAG_LONG) {
      37          25 :         avio_wl16(pb, 0);
      38          25 :         avio_wl32(pb, 0);
      39             :     } else {
      40          52 :         avio_wl16(pb, 0);
      41             :     }
      42          77 : }
      43             : 
      44          77 : static void put_swf_end_tag(AVFormatContext *s)
      45             : {
      46          77 :     SWFContext *swf = s->priv_data;
      47          77 :     AVIOContext *pb = s->pb;
      48             :     int64_t pos;
      49             :     int tag_len, tag;
      50             : 
      51          77 :     pos = avio_tell(pb);
      52          77 :     tag_len = pos - swf->tag_pos - 2;
      53          77 :     tag = swf->tag;
      54          77 :     avio_seek(pb, swf->tag_pos, SEEK_SET);
      55          77 :     if (tag & TAG_LONG) {
      56          25 :         tag &= ~TAG_LONG;
      57          25 :         avio_wl16(pb, (tag << 6) | 0x3f);
      58          25 :         avio_wl32(pb, tag_len - 4);
      59             :     } else {
      60          52 :         av_assert0(tag_len < 0x3f);
      61          52 :         avio_wl16(pb, (tag << 6) | tag_len);
      62             :     }
      63          77 :     avio_seek(pb, pos, SEEK_SET);
      64          77 : }
      65             : 
      66          10 : static inline void max_nbits(int *nbits_ptr, int val)
      67             : {
      68             :     int n;
      69             : 
      70          10 :     if (val == 0)
      71           6 :         return;
      72           4 :     val = FFABS(val);
      73           4 :     n = 1;
      74          68 :     while (val != 0) {
      75          60 :         n++;
      76          60 :         val >>= 1;
      77             :     }
      78           4 :     if (n > *nbits_ptr)
      79           2 :         *nbits_ptr = n;
      80             : }
      81             : 
      82           1 : static void put_swf_rect(AVIOContext *pb,
      83             :                          int xmin, int xmax, int ymin, int ymax)
      84             : {
      85             :     PutBitContext p;
      86             :     uint8_t buf[256];
      87             :     int nbits, mask;
      88             : 
      89           1 :     init_put_bits(&p, buf, sizeof(buf));
      90             : 
      91           1 :     nbits = 0;
      92           1 :     max_nbits(&nbits, xmin);
      93           1 :     max_nbits(&nbits, xmax);
      94           1 :     max_nbits(&nbits, ymin);
      95           1 :     max_nbits(&nbits, ymax);
      96           1 :     mask = (1 << nbits) - 1;
      97             : 
      98             :     /* rectangle info */
      99           1 :     put_bits(&p, 5, nbits);
     100           1 :     put_bits(&p, nbits, xmin & mask);
     101           1 :     put_bits(&p, nbits, xmax & mask);
     102           1 :     put_bits(&p, nbits, ymin & mask);
     103           1 :     put_bits(&p, nbits, ymax & mask);
     104             : 
     105           1 :     flush_put_bits(&p);
     106           1 :     avio_write(pb, buf, put_bits_ptr(&p) - p.buf);
     107           1 : }
     108             : 
     109           0 : static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
     110             : {
     111             :     int nbits, mask;
     112             : 
     113           0 :     put_bits(pb, 1, 1); /* edge */
     114           0 :     put_bits(pb, 1, 1); /* line select */
     115           0 :     nbits = 2;
     116           0 :     max_nbits(&nbits, dx);
     117           0 :     max_nbits(&nbits, dy);
     118             : 
     119           0 :     mask = (1 << nbits) - 1;
     120           0 :     put_bits(pb, 4, nbits - 2); /* 16 bits precision */
     121           0 :     if (dx == 0) {
     122           0 :         put_bits(pb, 1, 0);
     123           0 :         put_bits(pb, 1, 1);
     124           0 :         put_bits(pb, nbits, dy & mask);
     125           0 :     } else if (dy == 0) {
     126           0 :         put_bits(pb, 1, 0);
     127           0 :         put_bits(pb, 1, 0);
     128           0 :         put_bits(pb, nbits, dx & mask);
     129             :     } else {
     130           0 :         put_bits(pb, 1, 1);
     131           0 :         put_bits(pb, nbits, dx & mask);
     132           0 :         put_bits(pb, nbits, dy & mask);
     133             :     }
     134           0 : }
     135             : 
     136             : #define FRAC_BITS 16
     137             : 
     138           1 : static void put_swf_matrix(AVIOContext *pb,
     139             :                            int a, int b, int c, int d, int tx, int ty)
     140             : {
     141             :     PutBitContext p;
     142             :     uint8_t buf[256];
     143             :     int nbits;
     144             : 
     145           1 :     init_put_bits(&p, buf, sizeof(buf));
     146             : 
     147           1 :     put_bits(&p, 1, 1); /* a, d present */
     148           1 :     nbits = 1;
     149           1 :     max_nbits(&nbits, a);
     150           1 :     max_nbits(&nbits, d);
     151           1 :     put_bits(&p, 5, nbits); /* nb bits */
     152           1 :     put_bits(&p, nbits, a);
     153           1 :     put_bits(&p, nbits, d);
     154             : 
     155           1 :     put_bits(&p, 1, 1); /* b, c present */
     156           1 :     nbits = 1;
     157           1 :     max_nbits(&nbits, c);
     158           1 :     max_nbits(&nbits, b);
     159           1 :     put_bits(&p, 5, nbits); /* nb bits */
     160           1 :     put_bits(&p, nbits, c);
     161           1 :     put_bits(&p, nbits, b);
     162             : 
     163           1 :     nbits = 1;
     164           1 :     max_nbits(&nbits, tx);
     165           1 :     max_nbits(&nbits, ty);
     166           1 :     put_bits(&p, 5, nbits); /* nb bits */
     167           1 :     put_bits(&p, nbits, tx);
     168           1 :     put_bits(&p, nbits, ty);
     169             : 
     170           1 :     flush_put_bits(&p);
     171           1 :     avio_write(pb, buf, put_bits_ptr(&p) - p.buf);
     172           1 : }
     173             : 
     174           1 : static int swf_write_header(AVFormatContext *s)
     175             : {
     176           1 :     SWFContext *swf = s->priv_data;
     177           1 :     AVIOContext *pb = s->pb;
     178             :     PutBitContext p;
     179             :     uint8_t buf1[256];
     180             :     int i, width, height, rate, rate_base;
     181             :     int version;
     182             : 
     183           1 :     swf->sound_samples = 0;
     184           1 :     swf->swf_frame_number = 0;
     185           1 :     swf->video_frame_number = 0;
     186             : 
     187           2 :     for(i=0;i<s->nb_streams;i++) {
     188           1 :         AVCodecParameters *par = s->streams[i]->codecpar;
     189           1 :         if (par->codec_type == AVMEDIA_TYPE_AUDIO) {
     190           0 :             if (swf->audio_par) {
     191           0 :                 av_log(s, AV_LOG_ERROR, "SWF muxer only supports 1 audio stream\n");
     192           0 :                 return AVERROR_INVALIDDATA;
     193             :             }
     194           0 :             if (par->codec_id == AV_CODEC_ID_MP3) {
     195           0 :                 swf->audio_par = par;
     196           0 :                 swf->audio_fifo= av_fifo_alloc(AUDIO_FIFO_SIZE);
     197           0 :                 if (!swf->audio_fifo)
     198           0 :                     return AVERROR(ENOMEM);
     199             :             } else {
     200           0 :                 av_log(s, AV_LOG_ERROR, "SWF muxer only supports MP3\n");
     201           0 :                 return -1;
     202             :             }
     203             :         } else {
     204           1 :             if (swf->video_par) {
     205           0 :                 av_log(s, AV_LOG_ERROR, "SWF muxer only supports 1 video stream\n");
     206           0 :                 return AVERROR_INVALIDDATA;
     207             :             }
     208           2 :             if (par->codec_id == AV_CODEC_ID_VP6F ||
     209           1 :                 par->codec_id == AV_CODEC_ID_FLV1 ||
     210           0 :                 par->codec_id == AV_CODEC_ID_MJPEG) {
     211           1 :                 swf->video_st  = s->streams[i];
     212           1 :                 swf->video_par = par;
     213             :             } else {
     214           0 :                 av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n");
     215           0 :                 return -1;
     216             :             }
     217             :         }
     218             :     }
     219             : 
     220           1 :     if (!swf->video_par) {
     221             :         /* currently, cannot work correctly if audio only */
     222           0 :         width = 320;
     223           0 :         height = 200;
     224           0 :         rate = 10;
     225           0 :         rate_base= 1;
     226             :     } else {
     227           1 :         width = swf->video_par->width;
     228           1 :         height = swf->video_par->height;
     229             :         // TODO: should be avg_frame_rate
     230           1 :         rate = swf->video_st->time_base.den;
     231           1 :         rate_base = swf->video_st->time_base.num;
     232             :     }
     233             : 
     234           1 :     if (!swf->audio_par)
     235           1 :         swf->samples_per_frame = (44100LL * rate_base) / rate;
     236             :     else
     237           0 :         swf->samples_per_frame = (swf->audio_par->sample_rate * rate_base) / rate;
     238             : 
     239           1 :     avio_write(pb, "FWS", 3);
     240             : 
     241           1 :     if (!strcmp("avm2", s->oformat->name))
     242           0 :         version = 9;
     243           1 :     else if (swf->video_par && swf->video_par->codec_id == AV_CODEC_ID_VP6F)
     244           0 :         version = 8; /* version 8 and above support VP6 codec */
     245           1 :     else if (swf->video_par && swf->video_par->codec_id == AV_CODEC_ID_FLV1)
     246           1 :         version = 6; /* version 6 and above support FLV1 codec */
     247             :     else
     248           0 :         version = 4; /* version 4 for mpeg audio support */
     249           1 :     avio_w8(pb, version);
     250             : 
     251           1 :     avio_wl32(pb, DUMMY_FILE_SIZE); /* dummy size
     252             :                                       (will be patched if not streamed) */
     253             : 
     254           1 :     put_swf_rect(pb, 0, width * 20, 0, height * 20);
     255           1 :     if ((rate * 256LL) / rate_base >= (1<<16)) {
     256           0 :         av_log(s, AV_LOG_ERROR, "Invalid (too large) frame rate %d/%d\n", rate, rate_base);
     257           0 :         return AVERROR(EINVAL);
     258             :     }
     259           1 :     avio_wl16(pb, (rate * 256) / rate_base); /* frame rate */
     260           1 :     swf->duration_pos = avio_tell(pb);
     261           1 :     avio_wl16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
     262             : 
     263             :     /* avm2/swf v9 (also v8?) files require a file attribute tag */
     264           1 :     if (version == 9) {
     265           0 :         put_swf_tag(s, TAG_FILEATTRIBUTES);
     266           0 :         avio_wl32(pb, 1<<3); /* set ActionScript v3/AVM2 flag */
     267           0 :         put_swf_end_tag(s);
     268             :     }
     269             : 
     270             :     /* define a shape with the jpeg inside */
     271           1 :     if (swf->video_par && swf->video_par->codec_id == AV_CODEC_ID_MJPEG) {
     272           0 :         put_swf_tag(s, TAG_DEFINESHAPE);
     273             : 
     274           0 :         avio_wl16(pb, SHAPE_ID); /* ID of shape */
     275             :         /* bounding rectangle */
     276           0 :         put_swf_rect(pb, 0, width, 0, height);
     277             :         /* style info */
     278           0 :         avio_w8(pb, 1); /* one fill style */
     279           0 :         avio_w8(pb, 0x41); /* clipped bitmap fill */
     280           0 :         avio_wl16(pb, BITMAP_ID); /* bitmap ID */
     281             :         /* position of the bitmap */
     282           0 :         put_swf_matrix(pb, 1 << FRAC_BITS, 0,
     283             :                        0,  1 << FRAC_BITS, 0, 0);
     284           0 :         avio_w8(pb, 0); /* no line style */
     285             : 
     286             :         /* shape drawing */
     287           0 :         init_put_bits(&p, buf1, sizeof(buf1));
     288           0 :         put_bits(&p, 4, 1); /* one fill bit */
     289           0 :         put_bits(&p, 4, 0); /* zero line bit */
     290             : 
     291           0 :         put_bits(&p, 1, 0); /* not an edge */
     292           0 :         put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
     293           0 :         put_bits(&p, 5, 1); /* nbits */
     294           0 :         put_bits(&p, 1, 0); /* X */
     295           0 :         put_bits(&p, 1, 0); /* Y */
     296           0 :         put_bits(&p, 1, 1); /* set fill style 1 */
     297             : 
     298             :         /* draw the rectangle ! */
     299           0 :         put_swf_line_edge(&p, width, 0);
     300           0 :         put_swf_line_edge(&p, 0, height);
     301           0 :         put_swf_line_edge(&p, -width, 0);
     302           0 :         put_swf_line_edge(&p, 0, -height);
     303             : 
     304             :         /* end of shape */
     305           0 :         put_bits(&p, 1, 0); /* not an edge */
     306           0 :         put_bits(&p, 5, 0);
     307             : 
     308           0 :         flush_put_bits(&p);
     309           0 :         avio_write(pb, buf1, put_bits_ptr(&p) - p.buf);
     310             : 
     311           0 :         put_swf_end_tag(s);
     312             :     }
     313             : 
     314           1 :     if (swf->audio_par && swf->audio_par->codec_id == AV_CODEC_ID_MP3) {
     315           0 :         int v = 0;
     316             : 
     317             :         /* start sound */
     318           0 :         put_swf_tag(s, TAG_STREAMHEAD2);
     319           0 :         switch(swf->audio_par->sample_rate) {
     320           0 :         case 11025: v |= 1 << 2; break;
     321           0 :         case 22050: v |= 2 << 2; break;
     322           0 :         case 44100: v |= 3 << 2; break;
     323           0 :         default:
     324             :             /* not supported */
     325           0 :             av_log(s, AV_LOG_ERROR, "swf does not support that sample rate, choose from (44100, 22050, 11025).\n");
     326           0 :             return -1;
     327             :         }
     328           0 :         v |= 0x02; /* 16 bit playback */
     329           0 :         if (swf->audio_par->channels == 2)
     330           0 :             v |= 0x01; /* stereo playback */
     331           0 :         avio_w8(s->pb, v);
     332           0 :         v |= 0x20; /* mp3 compressed */
     333           0 :         avio_w8(s->pb, v);
     334           0 :         avio_wl16(s->pb, swf->samples_per_frame);  /* avg samples per frame */
     335           0 :         avio_wl16(s->pb, 0);
     336             : 
     337           0 :         put_swf_end_tag(s);
     338             :     }
     339             : 
     340           1 :     avio_flush(s->pb);
     341           1 :     return 0;
     342             : }
     343             : 
     344          25 : static int swf_write_video(AVFormatContext *s,
     345             :                            AVCodecParameters *par, const uint8_t *buf, int size)
     346             : {
     347          25 :     SWFContext *swf = s->priv_data;
     348          25 :     AVIOContext *pb = s->pb;
     349             : 
     350             :     /* Flash Player limit */
     351          25 :     if (swf->swf_frame_number == 16000)
     352           0 :         av_log(s, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
     353             : 
     354          50 :     if (par->codec_id == AV_CODEC_ID_VP6F ||
     355          25 :         par->codec_id == AV_CODEC_ID_FLV1) {
     356          25 :         if (swf->video_frame_number == 0) {
     357             :             /* create a new video object */
     358           1 :             put_swf_tag(s, TAG_VIDEOSTREAM);
     359           1 :             avio_wl16(pb, VIDEO_ID);
     360           1 :             swf->vframes_pos = avio_tell(pb);
     361           1 :             avio_wl16(pb, 15000); /* hard flash player limit */
     362           1 :             avio_wl16(pb, par->width);
     363           1 :             avio_wl16(pb, par->height);
     364           1 :             avio_w8(pb, 0);
     365           1 :             avio_w8(pb,ff_codec_get_tag(ff_swf_codec_tags, par->codec_id));
     366           1 :             put_swf_end_tag(s);
     367             : 
     368             :             /* place the video object for the first time */
     369           1 :             put_swf_tag(s, TAG_PLACEOBJECT2);
     370           1 :             avio_w8(pb, 0x36);
     371           1 :             avio_wl16(pb, 1);
     372           1 :             avio_wl16(pb, VIDEO_ID);
     373           1 :             put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
     374           1 :             avio_wl16(pb, swf->video_frame_number);
     375           1 :             avio_write(pb, "video", 5);
     376           1 :             avio_w8(pb, 0x00);
     377           1 :             put_swf_end_tag(s);
     378             :         } else {
     379             :             /* mark the character for update */
     380          24 :             put_swf_tag(s, TAG_PLACEOBJECT2);
     381          24 :             avio_w8(pb, 0x11);
     382          24 :             avio_wl16(pb, 1);
     383          24 :             avio_wl16(pb, swf->video_frame_number);
     384          24 :             put_swf_end_tag(s);
     385             :         }
     386             : 
     387             :         /* set video frame data */
     388          25 :         put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
     389          25 :         avio_wl16(pb, VIDEO_ID);
     390          25 :         avio_wl16(pb, swf->video_frame_number++);
     391          25 :         avio_write(pb, buf, size);
     392          25 :         put_swf_end_tag(s);
     393           0 :     } else if (par->codec_id == AV_CODEC_ID_MJPEG) {
     394           0 :         if (swf->swf_frame_number > 0) {
     395             :             /* remove the shape */
     396           0 :             put_swf_tag(s, TAG_REMOVEOBJECT);
     397           0 :             avio_wl16(pb, SHAPE_ID); /* shape ID */
     398           0 :             avio_wl16(pb, 1); /* depth */
     399           0 :             put_swf_end_tag(s);
     400             : 
     401             :             /* free the bitmap */
     402           0 :             put_swf_tag(s, TAG_FREECHARACTER);
     403           0 :             avio_wl16(pb, BITMAP_ID);
     404           0 :             put_swf_end_tag(s);
     405             :         }
     406             : 
     407           0 :         put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
     408             : 
     409           0 :         avio_wl16(pb, BITMAP_ID); /* ID of the image */
     410             : 
     411             :         /* a dummy jpeg header seems to be required */
     412           0 :         avio_wb32(pb, 0xffd8ffd9);
     413             :         /* write the jpeg image */
     414           0 :         avio_write(pb, buf, size);
     415             : 
     416           0 :         put_swf_end_tag(s);
     417             : 
     418             :         /* draw the shape */
     419             : 
     420           0 :         put_swf_tag(s, TAG_PLACEOBJECT);
     421           0 :         avio_wl16(pb, SHAPE_ID); /* shape ID */
     422           0 :         avio_wl16(pb, 1); /* depth */
     423           0 :         put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
     424           0 :         put_swf_end_tag(s);
     425             :     }
     426             : 
     427          25 :     swf->swf_frame_number++;
     428             : 
     429             :     /* streaming sound always should be placed just before showframe tags */
     430          25 :     if (swf->audio_par && av_fifo_size(swf->audio_fifo)) {
     431           0 :         int frame_size = av_fifo_size(swf->audio_fifo);
     432           0 :         put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
     433           0 :         avio_wl16(pb, swf->sound_samples);
     434           0 :         avio_wl16(pb, 0); // seek samples
     435           0 :         av_fifo_generic_read(swf->audio_fifo, pb, frame_size, (void*)avio_write);
     436           0 :         put_swf_end_tag(s);
     437             : 
     438             :         /* update FIFO */
     439           0 :         swf->sound_samples = 0;
     440             :     }
     441             : 
     442             :     /* output the frame */
     443          25 :     put_swf_tag(s, TAG_SHOWFRAME);
     444          25 :     put_swf_end_tag(s);
     445             : 
     446          25 :     return 0;
     447             : }
     448             : 
     449           0 : static int swf_write_audio(AVFormatContext *s,
     450             :                            AVCodecParameters *par, uint8_t *buf, int size)
     451             : {
     452           0 :     SWFContext *swf = s->priv_data;
     453             : 
     454             :     /* Flash Player limit */
     455           0 :     if (swf->swf_frame_number == 16000)
     456           0 :         av_log(s, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
     457             : 
     458           0 :     if (av_fifo_size(swf->audio_fifo) + size > AUDIO_FIFO_SIZE) {
     459           0 :         av_log(s, AV_LOG_ERROR, "audio fifo too small to mux audio essence\n");
     460           0 :         return -1;
     461             :     }
     462             : 
     463           0 :     av_fifo_generic_write(swf->audio_fifo, buf, size, NULL);
     464           0 :     swf->sound_samples += av_get_audio_frame_duration2(par, size);
     465             : 
     466             :     /* if audio only stream make sure we add swf frames */
     467           0 :     if (!swf->video_par)
     468           0 :         swf_write_video(s, par, 0, 0);
     469             : 
     470           0 :     return 0;
     471             : }
     472             : 
     473          25 : static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
     474             : {
     475          25 :     AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
     476          25 :     if (par->codec_type == AVMEDIA_TYPE_AUDIO)
     477           0 :         return swf_write_audio(s, par, pkt->data, pkt->size);
     478             :     else
     479          25 :         return swf_write_video(s, par, pkt->data, pkt->size);
     480             : }
     481             : 
     482           1 : static int swf_write_trailer(AVFormatContext *s)
     483             : {
     484           1 :     SWFContext *swf = s->priv_data;
     485           1 :     AVIOContext *pb = s->pb;
     486             :     AVCodecParameters *par, *video_par;
     487             :     int file_size, i;
     488             : 
     489           1 :     video_par = NULL;
     490           2 :     for(i=0;i<s->nb_streams;i++) {
     491           1 :         par = s->streams[i]->codecpar;
     492           1 :         if (par->codec_type == AVMEDIA_TYPE_VIDEO)
     493           1 :             video_par = par;
     494             :         else {
     495           0 :             av_fifo_freep(&swf->audio_fifo);
     496             :         }
     497             :     }
     498             : 
     499           1 :     put_swf_tag(s, TAG_END);
     500           1 :     put_swf_end_tag(s);
     501             : 
     502             :     /* patch file size and number of frames if not streamed */
     503           1 :     if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && video_par) {
     504           1 :         file_size = avio_tell(pb);
     505           1 :         avio_seek(pb, 4, SEEK_SET);
     506           1 :         avio_wl32(pb, file_size);
     507           1 :         avio_seek(pb, swf->duration_pos, SEEK_SET);
     508           1 :         avio_wl16(pb, swf->video_frame_number);
     509           1 :         if (swf->vframes_pos) {
     510           1 :         avio_seek(pb, swf->vframes_pos, SEEK_SET);
     511           1 :         avio_wl16(pb, swf->video_frame_number);
     512             :         }
     513           1 :         avio_seek(pb, file_size, SEEK_SET);
     514             :     }
     515           1 :     return 0;
     516             : }
     517             : 
     518             : #if CONFIG_SWF_MUXER
     519             : AVOutputFormat ff_swf_muxer = {
     520             :     .name              = "swf",
     521             :     .long_name         = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
     522             :     .mime_type         = "application/x-shockwave-flash",
     523             :     .extensions        = "swf",
     524             :     .priv_data_size    = sizeof(SWFContext),
     525             :     .audio_codec       = AV_CODEC_ID_MP3,
     526             :     .video_codec       = AV_CODEC_ID_FLV1,
     527             :     .write_header      = swf_write_header,
     528             :     .write_packet      = swf_write_packet,
     529             :     .write_trailer     = swf_write_trailer,
     530             :     .flags             = AVFMT_TS_NONSTRICT,
     531             : };
     532             : #endif
     533             : #if CONFIG_AVM2_MUXER
     534             : AVOutputFormat ff_avm2_muxer = {
     535             :     .name              = "avm2",
     536             :     .long_name         = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash) (AVM2)"),
     537             :     .mime_type         = "application/x-shockwave-flash",
     538             :     .priv_data_size    = sizeof(SWFContext),
     539             :     .audio_codec       = AV_CODEC_ID_MP3,
     540             :     .video_codec       = AV_CODEC_ID_FLV1,
     541             :     .write_header      = swf_write_header,
     542             :     .write_packet      = swf_write_packet,
     543             :     .write_trailer     = swf_write_trailer,
     544             :     .flags             = AVFMT_TS_NONSTRICT,
     545             : };
     546             : #endif

Generated by: LCOV version 1.13