📄 swf.c
字号:
/* Flash Player limit */ if ( swf->swf_frame_number == 16000 ) { av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); } if ( swf->audio_type ) { /* Prescan audio data for this swf frame */retry_swf_audio_packet: if ( ( swf->audio_size-outSize ) >= 4 ) { int mp3FrameSize = 0; int mp3SampleRate = 0; int mp3IsMono = 0; int mp3SamplesPerFrame = 0; /* copy out mp3 header from ring buffer */ uint8_t header[4]; for (c=0; c<4; c++) { header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE]; } if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) { if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) { outSize += mp3FrameSize; outSamples += mp3SamplesPerFrame; if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) { goto retry_swf_audio_packet; } } } else { /* invalid mp3 data, skip forward we need to do this since the Flash Player does not like custom headers */ swf->audio_in_pos ++; swf->audio_size --; swf->audio_in_pos %= AUDIO_FIFO_SIZE; goto retry_swf_audio_packet; } } /* audio stream is behind video stream, bail */ if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) { return 0; } } if ( swf->video_type == CODEC_ID_FLV1 ) { if ( swf->video_frame_number == 0 ) { /* create a new video object */ put_swf_tag(s, TAG_VIDEOSTREAM); put_le16(pb, VIDEO_ID); put_le16(pb, 15000 ); /* hard flash player limit */ put_le16(pb, enc->width); put_le16(pb, enc->height); put_byte(pb, 0); put_byte(pb, SWF_VIDEO_CODEC_FLV1); put_swf_end_tag(s); /* place the video object for the first time */ put_swf_tag(s, TAG_PLACEOBJECT2); put_byte(pb, 0x36); put_le16(pb, 1); put_le16(pb, VIDEO_ID); put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0); put_le16(pb, swf->video_frame_number ); put_byte(pb, 'v'); put_byte(pb, 'i'); put_byte(pb, 'd'); put_byte(pb, 'e'); put_byte(pb, 'o'); put_byte(pb, 0x00); put_swf_end_tag(s); } else { /* mark the character for update */ put_swf_tag(s, TAG_PLACEOBJECT2); put_byte(pb, 0x11); put_le16(pb, 1); put_le16(pb, swf->video_frame_number ); put_swf_end_tag(s); } /* set video frame data */ put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG); put_le16(pb, VIDEO_ID); put_le16(pb, swf->video_frame_number++ ); put_buffer(pb, buf, size); put_swf_end_tag(s); } else if ( swf->video_type == CODEC_ID_MJPEG ) { if (swf->swf_frame_number > 0) { /* remove the shape */ put_swf_tag(s, TAG_REMOVEOBJECT); put_le16(pb, SHAPE_ID); /* shape ID */ put_le16(pb, 1); /* depth */ put_swf_end_tag(s); /* free the bitmap */ put_swf_tag(s, TAG_FREECHARACTER); put_le16(pb, BITMAP_ID); put_swf_end_tag(s); } put_swf_tag(s, TAG_JPEG2 | TAG_LONG); put_le16(pb, BITMAP_ID); /* ID of the image */ /* a dummy jpeg header seems to be required */ put_byte(pb, 0xff); put_byte(pb, 0xd8); put_byte(pb, 0xff); put_byte(pb, 0xd9); /* write the jpeg image */ put_buffer(pb, buf, size); put_swf_end_tag(s); /* draw the shape */ put_swf_tag(s, TAG_PLACEOBJECT); put_le16(pb, SHAPE_ID); /* shape ID */ put_le16(pb, 1); /* depth */ put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0); put_swf_end_tag(s); } else { /* invalid codec */ } swf->swf_frame_number ++; swf->video_samples += swf->samples_per_frame; /* streaming sound always should be placed just before showframe tags */ if ( outSize > 0 ) { put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG); put_le16(pb, outSamples); put_le16(pb, 0); for (c=0; c<outSize; c++) { put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]); } put_swf_end_tag(s); /* update FIFO */ swf->sound_samples += outSamples; swf->audio_in_pos += outSize; swf->audio_size -= outSize; swf->audio_in_pos %= AUDIO_FIFO_SIZE; } /* output the frame */ put_swf_tag(s, TAG_SHOWFRAME); put_swf_end_tag(s); put_flush_packet(&s->pb); return 0;}static int swf_write_audio(AVFormatContext *s, AVCodecContext *enc, const uint8_t *buf, int size){ SWFContext *swf = s->priv_data; int c = 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"); } if (enc->codec_id == CODEC_ID_MP3 ) { for (c=0; c<size; c++) { swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c]; } swf->audio_size += size; swf->audio_out_pos += size; swf->audio_out_pos %= AUDIO_FIFO_SIZE; } /* if audio only stream make sure we add swf frames */ if ( swf->video_type == 0 ) { swf_write_video(s, enc, 0, 0); } return 0;}static int swf_write_packet(AVFormatContext *s, AVPacket *pkt){ AVCodecContext *codec = s->streams[pkt->stream_index]->codec; if (codec->codec_type == CODEC_TYPE_AUDIO) return swf_write_audio(s, codec, pkt->data, pkt->size); else return swf_write_video(s, codec, pkt->data, pkt->size);}static int swf_write_trailer(AVFormatContext *s){ SWFContext *swf = s->priv_data; ByteIOContext *pb = &s->pb; AVCodecContext *enc, *video_enc; int file_size, i; video_enc = NULL; for(i=0;i<s->nb_streams;i++) { enc = s->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_VIDEO) video_enc = enc; } put_swf_tag(s, TAG_END); put_swf_end_tag(s); put_flush_packet(&s->pb); /* patch file size and number of frames if not streamed */ if (!url_is_streamed(&s->pb) && video_enc) { file_size = url_ftell(pb); url_fseek(pb, 4, SEEK_SET); put_le32(pb, file_size); url_fseek(pb, swf->duration_pos, SEEK_SET); put_le16(pb, video_enc->frame_number); } av_free(swf->audio_fifo); return 0;}#endif //CONFIG_MUXERS/*********************************************//* Extract FLV encoded frame and MP3 from swf Note that the detection of the real frame is inaccurate at this point as it can be quite tricky to determine, you almost certainly will get a bad audio/video sync */static int get_swf_tag(ByteIOContext *pb, int *len_ptr){ int tag, len; if (url_feof(pb)) return -1; tag = get_le16(pb); len = tag & 0x3f; tag = tag >> 6; if (len == 0x3f) { len = get_le32(pb); }// av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len); *len_ptr = len; return tag;}static int swf_probe(AVProbeData *p){ /* check file header */ if (p->buf_size <= 16) return 0; if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' && p->buf[2] == 'S') return AVPROBE_SCORE_MAX; else return 0;}static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap){ SWFContext *swf = 0; ByteIOContext *pb = &s->pb; int nbits, len, frame_rate, tag, v; offset_t firstTagOff; AVStream *ast = 0; AVStream *vst = 0; swf = av_malloc(sizeof(SWFContext)); if (!swf) return -1; s->priv_data = swf; tag = get_be32(pb) & 0xffffff00; if (tag == MKBETAG('C', 'W', 'S', 0)) { av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n"); return AVERROR_IO; } if (tag != MKBETAG('F', 'W', 'S', 0)) return AVERROR_IO; get_le32(pb); /* skip rectangle size */ nbits = get_byte(pb) >> 3; len = (4 * nbits - 3 + 7) / 8; url_fskip(pb, len); frame_rate = get_le16(pb); get_le16(pb); /* frame count */ /* The Flash Player converts 8.8 frame rates to milliseconds internally. Do the same to get a correct framerate */ swf->ms_per_frame = ( 1000 * 256 ) / frame_rate; swf->samples_per_frame = 0; swf->ch_id = -1; firstTagOff = url_ftell(pb); for(;;) { tag = get_swf_tag(pb, &len); if (tag < 0) { if ( ast || vst ) { if ( vst && ast ) { vst->codec->time_base.den = ast->codec->sample_rate / swf->samples_per_frame; vst->codec->time_base.num = 1; } break; } av_log(s, AV_LOG_ERROR, "No media found in SWF\n"); return AVERROR_IO; } if ( tag == TAG_VIDEOSTREAM && !vst) { swf->ch_id = get_le16(pb); get_le16(pb); get_le16(pb); get_le16(pb); get_byte(pb); /* Check for FLV1 */ if ( get_byte(pb) == SWF_VIDEO_CODEC_FLV1 ) { vst = av_new_stream(s, 0); av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */ vst->codec->codec_type = CODEC_TYPE_VIDEO; vst->codec->codec_id = CODEC_ID_FLV1; if ( swf->samples_per_frame ) { vst->codec->time_base.den = 1000. / swf->ms_per_frame; vst->codec->time_base.num = 1; } } } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) { /* streaming found */ get_byte(pb); v = get_byte(pb); swf->samples_per_frame = get_le16(pb); if (len!=4) url_fskip(pb,len-4); /* if mp3 streaming found, OK */ if ((v & 0x20) != 0) { if ( tag == TAG_STREAMHEAD2 ) { get_le16(pb); } ast = av_new_stream(s, 1); av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */ if (!ast) return -ENOMEM; if (v & 0x01) ast->codec->channels = 2; else ast->codec->channels = 1; switch((v>> 2) & 0x03) { case 1: ast->codec->sample_rate = 11025; break; case 2: ast->codec->sample_rate = 22050; break; case 3: ast->codec->sample_rate = 44100; break; default: av_free(ast); return AVERROR_IO; } ast->codec->codec_type = CODEC_TYPE_AUDIO; ast->codec->codec_id = CODEC_ID_MP3; } } else { url_fskip(pb, len); } } url_fseek(pb, firstTagOff, SEEK_SET); return 0;}static int swf_read_packet(AVFormatContext *s, AVPacket *pkt){ SWFContext *swf = s->priv_data; ByteIOContext *pb = &s->pb; AVStream *st = 0; int tag, len, i, frame; for(;;) { tag = get_swf_tag(pb, &len); if (tag < 0) return AVERROR_IO; if (tag == TAG_VIDEOFRAME) { for( i=0; i<s->nb_streams; i++ ) { st = s->streams[i]; if (st->id == 0) { if ( get_le16(pb) == swf->ch_id ) { frame = get_le16(pb); av_get_packet(pb, pkt, len-4); pkt->pts = frame * swf->ms_per_frame; pkt->stream_index = st->index; return pkt->size; } else { url_fskip(pb, len-2); continue; } } } url_fskip(pb, len); } else if (tag == TAG_STREAMBLOCK) { for( i=0; i<s->nb_streams; i++ ) { st = s->streams[i]; if (st->id == 1) { av_get_packet(pb, pkt, len); pkt->stream_index = st->index; return pkt->size; } } url_fskip(pb, len); } else { url_fskip(pb, len); } } return 0;}static int swf_read_close(AVFormatContext *s){ return 0;}static AVInputFormat swf_iformat = { "swf", "Flash format", sizeof(SWFContext), swf_probe, swf_read_header, swf_read_packet, swf_read_close,};#ifdef CONFIG_MUXERSstatic AVOutputFormat swf_oformat = { "swf", "Flash format", "application/x-shockwave-flash", "swf", sizeof(SWFContext), CODEC_ID_MP3, CODEC_ID_FLV1, swf_write_header, swf_write_packet, swf_write_trailer,};#endif //CONFIG_MUXERSint swf_init(void){ av_register_input_format(&swf_iformat);#ifdef CONFIG_MUXERS av_register_output_format(&swf_oformat);#endif //CONFIG_MUXERS return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -