Как я могу сохранить MovieClip (растровое изображение и аудио) в FLV? - PullRequest
2 голосов
/ 05 января 2012

Это мой первый вопрос здесь: D, сначала прошу прощения за мой английский.

Мой вопрос в основном, как я могу сохранить Flash Movie Clip на FLV.

Movie Clip генерируетсяпользователями и имеет различные звуки и анимации, и мне нужно сохранить FLV для отправки его на Youtbue.

Что я пробовал: я нашел здесь несколько вопросов об использовании Lib Alchemy, который я использую, чтобы захватитьMovie Clip кадр за кадром и сохраните его в растровое изображение.

Alchemy Lib преобразует эти кадры в FLV как очарование и поддерживает сохранение фрагментов звука с помощью ByteArray.

В этой ситуации моя проблема в том, как я могу захватить звук Movie Clip, чтобы отправить его в Alchemy Lib?Я попытался использовать:

SoundMixer.computeSpectrum(sndData, false, 2);

Witch возвращает мне byteArray в переменной sndData, но бесполезно, поскольку оно используется для визуализации форм Audio Wave на экране.

Громкость при использовании

Sound.extract();

, но я считаю, что класс звука используется только для одного звука MP3, и мне нужно захватить смешанные звуки, сгенерированные Movie Clip.

Есть ли другой способ сгенерировать 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();


}

1 Ответ

1 голос
/ 09 января 2012

Готово!(Ну ... почти: D)

Это было сложно, но так как моей проблемой было только аудио MovieClip, я создал класс, который действует как микшер.

Микшер отвечает за воспроизведение всех звуков, используя уникальное событие SampleDataEvent, которое смешивает байты всех моих звуков.Также он генерирует отдельные звуковые данные в ByteArray, когда я выполняю функцию startRecording.Сложно объяснить, но вот код для микшера:

/**** 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 используется для воспроизведения и извлечения смешанных звуков одновременно.

Мне также пришлось создатьКласс MySound, расширяющий объект Sound для извлечения sampleData для каждого звука (метод getSampleData () ) в текущем буфере, используемом методом processSampleData .Класс MySound также начинает воспроизведение при запуске микшера (отправка 0 байтов для обоих каналов) и останавливается также, когда микшер останавливается, он начнет отправлять байтовую информацию о музыке только тогда, когда функция play () Позвонил.

Класс, который я создал, выглядит примерно так:

/**** 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, который содержит информацию о звуке отверстия микшера.все, что мне нужно было сделать, это запустить микшер при запуске мувиклипа и остановить его, когда мувиклип останавливается.Информация ByteArray со звуковым объектом передается addFrame (bitmapData, sndData) из Alchemy Lib, которая успешно записывает его.

В моем проекте это работает хорошо, но мне, вероятно, потребуется оптимизироватькод.

Спасибо всем, кто помог мне!

...