2012-01-04 100 views
2

这是我的第一个问题:D,首先抱歉我的英语。如何将MovieClip(位图和音频)保存到FLV?

我的问题基本上是如何保存Flash影片剪辑到FLV。

影片剪辑是由用户生成的,它有各种声音和动画,我需要保存一个FLV发送给Youtbue。

我试过了什么: 我在这里发现了一些关于使用Alchemy Lib的问题,我正在使用它来抓取Movie Clip帧并保存到Bitmap。

Alchemy Lib将这些帧转换为像FLV一样的魅力,并支持使用ByteArray保存声音块。

在这种情况下,我的问题是,我怎么能抓住电影剪辑的声音发送给炼金术宝? 从来就尝试使用:

SoundMixer.computeSpectrum(sndData, false, 2); 

女巫返回我sndData变量的ByteArray但无用的,因为用于it's呈现在屏幕上的音频波形。

阿布德吼声使用

Sound.extract(); 

,但我认为那声音类只能用于一个MP3的声音,我需要抓住的影片剪辑产生的混合声音。

是否有另一种方法从MovieClip生成FLV?

下面我的一些代码:

我根据我的教程下的代码,我在这个环节发现:http://www.zeropointnine.com/blog/updated-flv-encoder-alchem/

private const OUTPUT_WIDTH:Number = 550; 
private const OUTPUT_HEIGHT:Number = 400; 
private const FLV_FRAMERATE:int = 24; 
private var _baFlvEncoder:ByteArrayFlvEncoder;  
public var anime:MovieClip; 


//Starts recording 
public function startRecording() 
{ 
    this.addEventListener(Event.ENTER_FRAME, enterFrame); 

    //Initialize the Alchemy Lib 
    _baFlvEncoder = new ByteArrayFlvEncoder(stage.frameRate); 
    _baFlvEncoder.setVideoProperties(OUTPUT_WIDTH, OUTPUT_HEIGHT); 
    _baFlvEncoder.setAudioProperties(FlvEncoder.SAMPLERATE_22KHZ); 
    _baFlvEncoder.start();  

} 
//Stops recording 
public function stopRecording() 
{ 
    this.removeEventListener(Event.ENTER_FRAME, enterFrame); 
    _baFlvEncoder.updateDurationMetadata(); 

    // Save FLV file via FileReference 
    var fileRef:FileReference = new FileReference(); 
    fileRef.save(_baFlvEncoder.byteArray, "test.flv");   

    _baFlvEncoder.kill(); 

} 

//The Main Loop activated by StartRecording 
public function enterFrame(evt:Event) 
{ 
    var bmpData:BitmapData = new BitmapData(OUTPUT_WIDTH, OUTPUT_HEIGHT, false, 0xFFFFFFFF); 
    bmpData.draw(anime); 

    var sndData:ByteArray = new ByteArray(); 
    SoundMixer.computeSpectrum(sndData, false, 2); 

    _baFlvEncoder.addFrame(bmpData, sndData); 
    bmpData.dispose(); 


} 
+0

为什么你需要特别的FLV?你在使用Flash IDE吗?如果是这样,您可以将该电影导出为AVI(文件|导出|“导出电影...”)并以这种方式将其上传到YouTube。 – iND 2012-01-06 19:09:51

+0

目前没有可能,因为MovieClip只有soundTransform属性,但无法访问其声音对象。也许Adobe意向没有添加该功能,所以没有人能够在AS3中创建自己的swf2flv导出器。 – 2012-01-07 11:37:16

+0

我有一个想法如何做到这一点很难:它可能是声音数据与MovieClip对象存储在一起,所以你可能会尝试序列化为字节数组,然后挖掘字节码来找到声音数据并提取它:) – 2012-01-07 17:20:17

回答

1

做到了! (呃...差不多:D)

这很复杂,但由于我的问题只是MovieClip的音频,我创建了一个类似混音器的类。

调音台负责使用独特的SampleDataEvent播放所有声音,混合所有声音的字节。当我执行startRecording函数时,它还会在ByteArray中生成单个声音数据。 Kind很复杂的解释,但这里是混音器的代码:

/**** MySoundMixer initializations omitted ***/ 

//Generates the sound object to start the stream 
//for reproduce the mixed sounds. 
public function startStream() 
{ 
    fullStreamSound= new Sound(); 
    fullStreamSoundData = new ByteArray();    
    this.fullStreamSoundChannel = this.fullStreamSound.play(); 
} 

//Adds a sound in the soundlib 
//(See: MySound object for more details) 
public function addSound(sound:MySound, key:String) 
{ 
    sound.initialize(); 
    sounds.push({sound:sound, key:key}); 
} 

//Play a sound in the sound lib 
public function play(key) 
{ 
    var founded:MySound = null; 
    for (var i = 0; i < sounds.length; i++) 
    { 
     if (key == sounds[i].key) 
     { 
      founded = sounds[i].sound; 
      break; 
     } 
    } 
    if (founded != null) 
    { 
     founded.play(); 
    } 
} 

// The SampleDataEvent function to Play the sound and 
// if recording is activated record the sound to fullStreamSoundData 
public function processSampleData(event:SampleDataEvent) 
{ 
    var pos = 0; 

    var normValue:Number = 1/this.sounds.length; 
    while (pos < BUFFER) 
    { 

     var leftChannel:Number = 0; 
     var rightChannel:Number = 0; 

     for (var i = 0; i < this.sounds.length; i++) 
     { 
      var currentSound:MySound = this.sounds[i].sound; 
      var result = currentSound.getSampleData(); 
      leftChannel += result.leftChannel * normValue; 
      rightChannel += result.rightChannel * normValue; 
     } 

     event.data.writeFloat(leftChannel); 
     event.data.writeFloat(rightChannel); 

     if (isRecording) 
     { 
      fullStreamSoundData.writeFloat(leftChannel); 
      fullStreamSoundData.writeFloat(rightChannel); 
     } 

     pos++; 
    } 
} 

//Starts recording 
public function startRecording() 
{ 
    this.isRecording = true; 
} 

//Stops recording 
public function stopRecording() 
{ 
    this.isRecording = false; 
} 

SampleDataEvent用于播放并同时提取混合声音。

我还必须创建一个扩展声音对象,以便在由的ProcessSampleData方法中使用当前缓冲器来提取()方法getSampleData()每个声音的一个的sampleData类为mySound。 MySound类也会在混音器启动时开始播放(发送两个频道的0字节),并且在混音器停止时也会停止,只有在调用播放()函数时才会开始发送音乐的字节信息。

,我已创建的类是这样的:

/**** MySound initializations omitted ***/ 
public function initialize() 
{ 
    this.extractInformation(null); 
} 

//Override the play function to avoid playing. 
//(The play act will be triggered by SoundMixer class) 
override public function play(startTime:Number = 0, loops:int = 0, sndTransform:SoundTransform = null):SoundChannel 
{ 
    this.isPlaying = true; 
    this.currentPhase = 0; 
    return null; 
} 

// On each buffer in sampledata i read the chunk of sound bytes 
public function getSampleData() 
{ 
    var leftChannel:Number = 0; 
    var rightChannel:Number = 0; 
    if (this.isPlaying) { 
     if (currentPhase < totalPhases) 
     { 
      this.soundData.position = currentPhase * 8; 
      leftChannel = this.soundData.readFloat(); 
      rightChannel = this.soundData.readFloat(); 
      this.currentPhase ++; 
     } else 
     { 
      stopPlaying(); 
     } 
    } 
    return { leftChannel:leftChannel, rightChannel:rightChannel }; 
} 

//Extracts information of the sound object in order to 
//split it in several chunks of sounds. 
public function extractInformation(evt:Event) 
{ 
    trace("Inicializando o som " + this.id3); 
    this.soundData = new ByteArray(); 
    this.extract(soundData, int(this.length * SAMPLE_44HZ + 10000)); 
    this.totalPhases = this.soundData.length/8; 
    this.currentPhase = 0; 
} 

///Stop playing means stop extracting bytes 
public function stopPlaying() 
{ 
    this.isPlaying = false; 
} 

下面我生成包含混频器的孔的声音信息的唯一字节阵列对象。 我所要做的就是在电影剪辑开始时启动调音台,并在电影剪辑停止时停止。 带声音对象的ByteArray信息传递给Alchemy Lib的addFrame(bitmapData,sndData),成功记录它。

它在我的项目中运行良好,但我可能需要优化代码。

谢谢所有帮助我的家伙!