📄 swf.c
字号:
/* * Flash Compatible Streaming Format * Copyright (c) 2000 Fabrice Bellard. * Copyright (c) 2003 Tinic Uro. * * This file is part of FFmpeg. * * FFmpeg 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.1 of the License, or (at your option) any later version. * * FFmpeg 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 FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */#include "avformat.h"#include "bitstream.h"#include "riff.h" /* for CodecTag *//* 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 18#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_FILEATTRIBUTES 69#define TAG_LONG 0x100/* flags for shape definition */#define FLAG_MOVETO 0x01#define FLAG_SETFILL0 0x02#define FLAG_SETFILL1 0x04#define AUDIO_FIFO_SIZE 65536/* character id used */#define BITMAP_ID 0#define VIDEO_ID 0#define SHAPE_ID 1#undef NDEBUG#include <assert.h>typedef struct { int audio_stream_index; offset_t duration_pos; offset_t tag_pos; int samples_per_frame; int sound_samples; int swf_frame_number; int video_frame_number; int frame_rate; int tag; uint8_t audio_fifo[AUDIO_FIFO_SIZE]; int audio_in_pos; int video_type; int audio_type;} SWFContext;static const AVCodecTag swf_codec_tags[] = { {CODEC_ID_FLV1, 0x02}, {CODEC_ID_VP6F, 0x04}, {0, 0},};static const AVCodecTag swf_audio_codec_tags[] = { {CODEC_ID_PCM_S16LE, 0x00}, {CODEC_ID_ADPCM_SWF, 0x01}, {CODEC_ID_MP3, 0x02}, {CODEC_ID_PCM_S16LE, 0x03}, //{CODEC_ID_NELLYMOSER, 0x06}, {0, 0},};#ifdef CONFIG_MUXERSstatic 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 = s->priv_data; ByteIOContext *pb = s->pb; AVCodecContext *enc, *audio_enc, *video_enc; PutBitContext p; uint8_t buf1[256]; int i, width, height, rate, rate_base; int is_avm2; swf->audio_in_pos = 0; swf->sound_samples = 0; swf->swf_frame_number = 0; swf->video_frame_number = 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) { if (enc->codec_id == CODEC_ID_MP3) { if (!enc->frame_size) { av_log(s, AV_LOG_ERROR, "audio frame size not set\n"); return -1; } audio_enc = enc; } else { av_log(s, AV_LOG_ERROR, "SWF muxer only supports MP3\n"); return -1; } } else { if (enc->codec_id == CODEC_ID_VP6F || enc->codec_id == CODEC_ID_FLV1 || enc->codec_id == CODEC_ID_MJPEG) { video_enc = enc; } else { av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n"); return -1; } } } if (!video_enc) { /* currently, 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->time_base.den; rate_base = video_enc->time_base.num; } 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; } is_avm2 = !strcmp("avm2", s->oformat->name); put_tag(pb, "FWS"); if (is_avm2) { put_byte(pb, 9); } else if (video_enc && video_enc->codec_id == CODEC_ID_VP6F) { put_byte(pb, 8); /* version (version 8 and above support VP6 codec) */ } else 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 */ /* avm2/swf v9 (also v8?) files require a file attribute tag */ if (is_avm2) { put_swf_tag(s, TAG_FILEATTRIBUTES); put_le32(pb, 1<<3); /* set ActionScript v3/AVM2 flag */ put_swf_end_tag(s); } /* define a shape with the jpeg inside */ if (video_enc && (video_enc->codec_id == CODEC_ID_VP6F || 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_log(s, AV_LOG_ERROR, "swf does not support that sample rate, choose from (44100, 22050, 11025).\n"); 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -