$30 off During Our Annual Pro Sale. View Details »

PHPとRustを組み合わせて音声ファイルをエンコードする話

 PHPとRustを組み合わせて音声ファイルをエンコードする話

PHPerKaigi 2020
https://phperkaigi.jp/2020/

Shumpei Urabe
PRO

February 11, 2020
Tweet

More Decks by Shumpei Urabe

Other Decks in Technology

Transcript

  1. PHPͱRustΛ૊Έ߹ΘͤͯԻ੠
    ϑΝΠϧΛΤϯίʔυ͢Δ࿩
    PHPerKaigi 2020 LT
    @yaminoma_tw

    View Slide

  2. Shumpei Urabe (@yaminoma_tw)
    ޷͖ͳϑϨʔϜϫʔΫ͸
    BEAR.Sunday
    PHPerݟश͍

    View Slide

  3. PHP FFIͷ͓͸ͳ͠

    View Slide

  4. FFIͱ͸ʁ
    • PHPҎ֎ͷݴޠͰ࣮૷͞ΕͨωΠςΟϒίʔυΛݺͼग़͢͜ͱ
    ͕Ͱ͖Δ࢓૊Έ
    • FFI͸ωΠςΟϒ࣮ߦͳͷͰɺύϑΥʔϚϯεͷ޲্͕ظ଴Ͱ͖
    Δ

    View Slide

  5. PHP FFIͷྺ࢙
    • Ҏલ͔ΒPECLͰFFIͷΤΫεςϯγϣϯ͸͋ͬͨ
    • ͔͠͠ɺ10೥Ҏ্ߋ৽͞Ε͍ͯͳ͍ঢ়گͰ์ஔ͞Ε͍ͯͨ

    View Slide

  6. PHP FFIͷྺ࢙
    • ͦ͜ͰZendࣾͷDmitry Stogovࢯ͸ɺlibffiΛ࢖֦ͬͨுΛ։ൃͨ͠
    • 2019೥1݄ʹࢍ੒24ɺ൓ର15ͱ͍͏ൺֱతᷮࠩͰPHP 7.4΁ͷ࠾༻
    ͕ܾ·Γɺ͜ͷ֦ு͕ແࣄPHP 7.4ʹऔΓࠐ·Εͨ
    • ͦͷ݁ՌɺPECLͷFFIΤΫεςϯγϣϯʹൺ΂ΔͱɺΠϯλʔϑΣ
    ΠεͷΈهड़͢Δ͚ͩͰग़དྷΔΑ͏ʹͳͬͨ

    View Slide

  7. ຊ୊

    View Slide

  8. PHPͰԻ੠ϑΝΠϧΛΤϯίʔυͯ͠ΈΔ
    • Ի੠ϑΝΠϧͷΤϯίʔυͱ͍͑͹FFmpeg͕ఆ൪Ͱ͋Δ
    • FFmpegͷίϚϯυΛexecͰୟ͘ͷ͸؆୯Ͱ͸͋Δ͕ɺexecͰ
    ࣮ߦͨ͘͠ͳ͍ͱ͖΋͋Δ
    • PHP୯ମͰԻ੠ϑΝΠϧΛΤϯίʔυͰ͖Δͱ௒ศརʂ

    View Slide

  9. ͱ͍͏͜ͱͰ࡞Γ·ͨ͠

    View Slide

  10. php-mp3-encoder
    • https://github.com/yaminoma/php-mp3-encoder
    • RustͰMP3ͷΤϯίʔμʔͰ͋Δlibmp3lameΛ࢖ͬͯɺWAVϑΝ
    Πϧ͔ΒMP3ʹΤϯίʔυ͢Δαϯϓϧ
    • ͜ͷlibmp3lame΋bindgenΛ࢖ͬͯRust͔ΒFFIͰݺͼग़͍ͯ͠Δ

    View Slide

  11. ͘͠Έ

    View Slide

  12. wavͷத਎Λ
    uint8_t* Ͱ౉͢
    Τϯίʔυͨ͠ϑΝΠϧ໊Λ
    char* Ͱ౉͢

    View Slide

  13. PHPͰFFIΛ༗ޮʹͯ͠ΈΔ
    git clone https://github.com/php/php-src.git
    cd php-src
    git checkout PHP-7.4
    ./configure --with-ffi
    make

    View Slide

  14. PHPͰFFIΛ༗ޮʹͯ͠ΈΔ
    • σϑΥϧτ͸ ffi.enable=preload ʹͳ͓ͬͯΓɺϓϦϩʔυΛ
    ߦͬͨؔ਺·ͨ͸CLIΠϯλʔϑΣΠεͰͷΈFFIػೳΛ࢖༻͢
    Δ͜ͱ͕Մೳ
    • ffi.enable=trueʹ͢ΔͱɺશͯͷFFIͷػೳΛ࢖͏͜ͱ͕ग़དྷΔ

    View Slide

  15. RustͰΤϯίʔυ͢Δ෦෼Λ࣮૷͢Δ
    #[no_mangle]
    pub extern "C" fn encode(data: *mut u8, length: u32) -> *const c_char {
    unsafe {
    let buf: &mut [u8] = core::slice::from_raw_parts_mut(data, length as usize);
    let mut ptr = io::Cursor::new(buf);
    let mut wav_reader = hound::WavReader::new(&mut ptr).unwrap();
    let mut data = Vec::new();
    for sample in wav_reader.samples() {
    match sample {
    Ok(smpl) => data.push(smpl),
    _ => panic!("failed"),
    }
    }
    let timestamp = Rational64::from_integer(0);
    let raw_frame = RawFrame { timestamp, data };
    let mut encoder = Encoder::new();
    let output_file_name = encoder.encode(raw_frame);
    return CString::new(output_file_name)
    .expect("failed")
    .into_raw();
    }
    }

    View Slide

  16. RustͰdylibΛϏϧυͯ͠PHPͰαʔϒ͢Δ
    $ cargo build --release
    $ php -d ffi.enable=1 -S localhost:8000 -t src

    View Slide

  17. μΠφϛοΫϥΠϒϥϦΛಡΈࠐΉ
    $signature = "const char* encode(uint8_t *data, uint32_t
    length);";
    return \FFI::cdef( $signature, __DIR__ . "/../target/
    release/libmp3encoder.dylib");

    View Slide

  18. freadͰϑΝΠϧΛಡΈऔΔ
    $file = $_FILES['audio_file']['tmp_name'];
    $handle = fopen($file, "rb");
    $fsize = filesize($file);
    $value = fread($handle, $fsize);

    View Slide

  19. FFIͷݺͼग़͠ͱ࣮ߦ
    $ffi = loadLibrary();
    $length = \strlen($value);
    $buffer = FFI::new(FFI::arrayType($ffi->type('uint8_t'),
    [$length]));
    FFI::memcpy($buffer, $value, $length);
    $bufferPtr = FFI::cast($ffi->type('uint8_t*'), $buffer);
    $outputFileName = $ffi->encode($bufferPtr, $length);

    View Slide

  20. ݁Ռ
    • 5෼ͷۂ͕େମ8ඵ͘Β͍Ͱม׵͕ऴΘͬͨ
    • PHPͷFFIͷυΩϡϝϯτ͕৘ใྔগͳͯ݁͘ߏۤ͠Μͩ
    • FFI͕༗ޮʹͳ͍ͬͯΕ͹ͲͷαʔόͰ΋MP3͕ΤϯίʔυͰ͖
    Δʂ

    View Slide

  21. FFIͷকདྷ
    • ܭࢉྔͷଟ͍ϓϩάϥϜΛFFIͰݺͼग़͢ͱྑ͍͔΋͠Εͳ͍
    • ·ͩ·࣮ͩݧతͳཁૉ͕ଟ͍ͷͰɺϓϩμΫγϣϯϨσΟʔͰ
    ͸ͳ͍
    • ͜Ε͔Βଞͷݴޠͱ૊Έ߹ΘͤͯPHP͕΋ͬͱ੝Γ্͕͍ͬͯ
    ͖͍ͨʂ

    View Slide

  22. ͓͠·͍

    View Slide