📄 swf.c
字号:
/* * Flash Compatible Streaming Format * Copyright (c) 2000 Fabrice Bellard. * Copyright (c) 2003 Tinic Uro. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "avformat.h"/* should have a generic way to indicate probable size */#define DUMMY_FILE_SIZE (100 * 1024 * 1024)#define DUMMY_DURATION 600 /* in seconds */#define TAG_END 0#define TAG_SHOWFRAME 1#define TAG_DEFINESHAPE 2#define TAG_FREECHARACTER 3#define TAG_PLACEOBJECT 4#define TAG_REMOVEOBJECT 5#define TAG_STREAMHEAD 45#define TAG_STREAMBLOCK 19#define TAG_JPEG2 21#define TAG_PLACEOBJECT2 26#define TAG_STREAMHEAD2 45#define TAG_VIDEOSTREAM 60#define TAG_VIDEOFRAME 61#define TAG_LONG 0x100/* flags for shape definition */#define FLAG_MOVETO 0x01#define FLAG_SETFILL0 0x02#define FLAG_SETFILL1 0x04#define SWF_VIDEO_CODEC_FLV1 0x02#define AUDIO_FIFO_SIZE 65536/* character id used */#define BITMAP_ID 0#define VIDEO_ID 0#define SHAPE_ID 1typedef struct SWFFrame_s { void *data; int size; struct SWFFrame_s *prev; struct SWFFrame_s *next;} SWFFrame;typedef struct { offset_t duration_pos; offset_t tag_pos; int samples_per_frame; int sound_samples; int video_samples; int skip_samples; int swf_frame_number; int video_frame_number; int ms_per_frame; int ch_id; int tag; uint8_t *audio_fifo; int audio_in_pos; int audio_out_pos; int audio_size; int video_type; int audio_type; SWFFrame *frame_head; SWFFrame *frame_tail;} SWFContext;static const int sSampleRates[3][4] = { {44100, 48000, 32000, 0}, {22050, 24000, 16000, 0}, {11025, 12000, 8000, 0},};static const int sBitRates[2][3][15] = { { { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448}, { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384}, { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320} }, { { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256}, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160} },};static const int sSamplesPerFrame[3][3] ={ { 384, 1152, 1152 }, { 384, 1152, 576 }, { 384, 1152, 576 }};static const int sBitsPerSlot[3] = { 32, 8, 8};static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono ){ uint8_t *dataTmp = (uint8_t *)data; uint32_t header = ( (uint32_t)dataTmp[0] << 24 ) | ( (uint32_t)dataTmp[1] << 16 ) | ( (uint32_t)dataTmp[2] << 8 ) | (uint32_t)dataTmp[3]; int layerID = 3 - ((header >> 17) & 0x03); int bitRateID = ((header >> 12) & 0x0f); int sampleRateID = ((header >> 10) & 0x03); int bitRate = 0; int bitsPerSlot = sBitsPerSlot[layerID]; int isPadded = ((header >> 9) & 0x01); if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) { return 0; } *isMono = ((header >> 6) & 0x03) == 0x03; if ( (header >> 19 ) & 0x01 ) { *sampleRate = sSampleRates[0][sampleRateID]; bitRate = sBitRates[0][layerID][bitRateID] * 1000; *samplesPerFrame = sSamplesPerFrame[0][layerID]; } else { if ( (header >> 20) & 0x01 ) { *sampleRate = sSampleRates[1][sampleRateID]; bitRate = sBitRates[1][layerID][bitRateID] * 1000; *samplesPerFrame = sSamplesPerFrame[1][layerID]; } else { *sampleRate = sSampleRates[2][sampleRateID]; bitRate = sBitRates[1][layerID][bitRateID] * 1000; *samplesPerFrame = sSamplesPerFrame[2][layerID]; } } *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) ); return 1;}#ifdef CONFIG_ENCODERSstatic void put_swf_tag(AVFormatContext *s, int tag){ SWFContext *swf = s->priv_data; ByteIOContext *pb = &s->pb; swf->tag_pos = url_ftell(pb); swf->tag = tag; /* reserve some room for the tag */ if (tag & TAG_LONG) { put_le16(pb, 0); put_le32(pb, 0); } else { put_le16(pb, 0); }}static void put_swf_end_tag(AVFormatContext *s){ SWFContext *swf = s->priv_data; ByteIOContext *pb = &s->pb; offset_t pos; int tag_len, tag; pos = url_ftell(pb); tag_len = pos - swf->tag_pos - 2; tag = swf->tag; url_fseek(pb, swf->tag_pos, SEEK_SET); if (tag & TAG_LONG) { tag &= ~TAG_LONG; put_le16(pb, (tag << 6) | 0x3f); put_le32(pb, tag_len - 4); } else { assert(tag_len < 0x3f); put_le16(pb, (tag << 6) | tag_len); } url_fseek(pb, pos, SEEK_SET);}static inline void max_nbits(int *nbits_ptr, int val){ int n; if (val == 0) return; val = abs(val); n = 1; while (val != 0) { n++; val >>= 1; } if (n > *nbits_ptr) *nbits_ptr = n;}static void put_swf_rect(ByteIOContext *pb, int xmin, int xmax, int ymin, int ymax){ PutBitContext p; uint8_t buf[256]; int nbits, mask; init_put_bits(&p, buf, sizeof(buf)); nbits = 0; max_nbits(&nbits, xmin); max_nbits(&nbits, xmax); max_nbits(&nbits, ymin); max_nbits(&nbits, ymax); mask = (1 << nbits) - 1; /* rectangle info */ put_bits(&p, 5, nbits); put_bits(&p, nbits, xmin & mask); put_bits(&p, nbits, xmax & mask); put_bits(&p, nbits, ymin & mask); put_bits(&p, nbits, ymax & mask); flush_put_bits(&p); put_buffer(pb, buf, pbBufPtr(&p) - p.buf);}static void put_swf_line_edge(PutBitContext *pb, int dx, int dy){ int nbits, mask; put_bits(pb, 1, 1); /* edge */ put_bits(pb, 1, 1); /* line select */ nbits = 2; max_nbits(&nbits, dx); max_nbits(&nbits, dy); mask = (1 << nbits) - 1; put_bits(pb, 4, nbits - 2); /* 16 bits precision */ if (dx == 0) { put_bits(pb, 1, 0); put_bits(pb, 1, 1); put_bits(pb, nbits, dy & mask); } else if (dy == 0) { put_bits(pb, 1, 0); put_bits(pb, 1, 0); put_bits(pb, nbits, dx & mask); } else { put_bits(pb, 1, 1); put_bits(pb, nbits, dx & mask); put_bits(pb, nbits, dy & mask); }}#define FRAC_BITS 16/* put matrix */static void put_swf_matrix(ByteIOContext *pb, int a, int b, int c, int d, int tx, int ty){ PutBitContext p; uint8_t buf[256]; int nbits; init_put_bits(&p, buf, sizeof(buf)); put_bits(&p, 1, 1); /* a, d present */ nbits = 1; max_nbits(&nbits, a); max_nbits(&nbits, d); put_bits(&p, 5, nbits); /* nb bits */ put_bits(&p, nbits, a); put_bits(&p, nbits, d); put_bits(&p, 1, 1); /* b, c present */ nbits = 1; max_nbits(&nbits, c); max_nbits(&nbits, b); put_bits(&p, 5, nbits); /* nb bits */ put_bits(&p, nbits, c); put_bits(&p, nbits, b); nbits = 1; max_nbits(&nbits, tx); max_nbits(&nbits, ty); put_bits(&p, 5, nbits); /* nb bits */ put_bits(&p, nbits, tx); put_bits(&p, nbits, ty); flush_put_bits(&p); put_buffer(pb, buf, pbBufPtr(&p) - p.buf);}/* */static int swf_write_header(AVFormatContext *s){ SWFContext *swf; ByteIOContext *pb = &s->pb; AVCodecContext *enc, *audio_enc, *video_enc; PutBitContext p; uint8_t buf1[256]; int i, width, height, rate, rate_base; swf = av_malloc(sizeof(SWFContext)); if (!swf) return -1; s->priv_data = swf; swf->ch_id = -1; swf->audio_in_pos = 0; swf->audio_out_pos = 0; swf->audio_size = 0; swf->audio_fifo = av_malloc(AUDIO_FIFO_SIZE); swf->frame_head = 0; swf->frame_tail = 0; swf->sound_samples = 0; swf->video_samples = 0; swf->swf_frame_number = 0; swf->video_frame_number = 0; swf->skip_samples = 0; video_enc = NULL; audio_enc = NULL; for(i=0;i<s->nb_streams;i++) { enc = &s->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_AUDIO) audio_enc = enc; else { if ( enc->codec_id == CODEC_ID_FLV1 || enc->codec_id == CODEC_ID_MJPEG ) { video_enc = enc; } else { av_log(enc, AV_LOG_ERROR, "SWF only supports FLV1 and MJPEG\n"); return -1; } } } if (!video_enc) { /* currenty, cannot work correctly if audio only */ swf->video_type = 0; width = 320; height = 200; rate = 10; rate_base= 1; } else { swf->video_type = video_enc->codec_id; width = video_enc->width; height = video_enc->height; rate = video_enc->frame_rate; rate_base = video_enc->frame_rate_base; } if (!audio_enc ) { swf->audio_type = 0; swf->samples_per_frame = ( 44100. * rate_base ) / rate; } else { swf->audio_type = audio_enc->codec_id; swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate; } put_tag(pb, "FWS"); if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) { put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */ } else { put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */ } put_le32(pb, DUMMY_FILE_SIZE); /* dummy size (will be patched if not streamed) */ put_swf_rect(pb, 0, width * 20, 0, height * 20); put_le16(pb, (rate * 256) / rate_base); /* frame rate */ swf->duration_pos = url_ftell(pb); put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */ /* define a shape with the jpeg inside */ if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) { } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) { put_swf_tag(s, TAG_DEFINESHAPE); put_le16(pb, SHAPE_ID); /* ID of shape */ /* bounding rectangle */ put_swf_rect(pb, 0, width, 0, height); /* style info */ put_byte(pb, 1); /* one fill style */ put_byte(pb, 0x41); /* clipped bitmap fill */ put_le16(pb, BITMAP_ID); /* bitmap ID */ /* position of the bitmap */ put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0, 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0); put_byte(pb, 0); /* no line style */ /* shape drawing */ init_put_bits(&p, buf1, sizeof(buf1)); put_bits(&p, 4, 1); /* one fill bit */ put_bits(&p, 4, 0); /* zero line bit */ put_bits(&p, 1, 0); /* not an edge */ put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0); put_bits(&p, 5, 1); /* nbits */ put_bits(&p, 1, 0); /* X */ put_bits(&p, 1, 0); /* Y */ put_bits(&p, 1, 1); /* set fill style 1 */ /* draw the rectangle ! */ put_swf_line_edge(&p, width, 0); put_swf_line_edge(&p, 0, height); put_swf_line_edge(&p, -width, 0); put_swf_line_edge(&p, 0, -height); /* end of shape */ put_bits(&p, 1, 0); /* not an edge */ put_bits(&p, 5, 0); flush_put_bits(&p); put_buffer(pb, buf1, pbBufPtr(&p) - p.buf); put_swf_end_tag(s); } if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) { int v; /* start sound */ put_swf_tag(s, TAG_STREAMHEAD2); v = 0; switch(audio_enc->sample_rate) { case 11025: v |= 1 << 2; break; case 22050: v |= 2 << 2; break; case 44100: v |= 3 << 2; break; default: /* not supported */ av_free(swf->audio_fifo); av_free(swf); return -1; } v |= 0x02; /* 16 bit playback */ if (audio_enc->channels == 2) v |= 0x01; /* stereo playback */ put_byte(&s->pb, v); v |= 0x20; /* mp3 compressed */ put_byte(&s->pb, v); put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */ put_le16(&s->pb, 0); put_swf_end_tag(s); } put_flush_packet(&s->pb); return 0;}static int swf_write_video(AVFormatContext *s, AVCodecContext *enc, const uint8_t *buf, int size){ SWFContext *swf = s->priv_data; ByteIOContext *pb = &s->pb; int c = 0; int outSize = 0; int outSamples = 0; /* Flash Player limit */ if ( swf->swf_frame_number == 16000 ) { av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); } /* Store video data in queue */ if ( enc->codec_type == CODEC_TYPE_VIDEO ) { SWFFrame *new_frame = av_malloc(sizeof(SWFFrame)); new_frame->prev = 0; new_frame->next = swf->frame_head; new_frame->data = av_malloc(size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -