動画からテキストを抽出する簡単な実装

動画からテキストを抽出するプロセスを簡潔に説明します。このプロセスは以下の3つのステップで構成されています:

  1. 動画ファイルの取得
  2. 音声の分離
  3. 音声からテキストへの変換

まず、動画ファイルをダウンロードするためのコードを示します。このコードはURLから動画ファイルをダウンロードし、そのInputStreamを返します。

public InputStream downloadVideo(String videoUrl) {
    InputStream videoInputStream = null;
    try {
        String fileName = "video-" + System.currentTimeMillis() + "-" + UUID.randomUUID().toString() + ".mp4";
        File tempFolder = new File("temp");
        if (!tempFolder.exists()) {
            tempFolder.mkdir();
        }
        File videoFile = HttpUtil.downloadFileFromUrl(videoUrl, new File(tempFolder, fileName), new StreamProgress() {
            @Override
            public void start() {
                log.info("Start downloading file...");
            }

            @Override
            public void progress(long total) {
                // プログレス情報をログに出力
            }

            @Override
            public void finish() {
                log.info("File downloaded successfully!");
            }
        });
        videoInputStream = new FileInputStream(videoFile);
        videoFile.delete();
    } catch (Exception e) {
        log.error("Failed to get video stream: {}", videoUrl, e);
        throw new BusinessException(ErrorCodeEnum.DOWNLOAD_VIDEO_ERROR.code(), "Failed to get video stream");
    }
    return videoInputStream;
}

次に、JavaCVを使用して音声を分離するコードです。FFmpegFrameRecorderとFFmpegFrameGrabberを使用して音声データを抽出します。

public ExtractAudioRes extractAudio(InputStream videoInputStream) throws Exception {
    ByteArrayOutputStream audioOutputStream = new ByteArrayOutputStream();

    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(audioOutputStream, 2);
    recorder.setAudioOption("crf", "0");
    recorder.setAudioQuality(0);
    recorder.setAudioBitrate(256000);
    recorder.setSampleRate(8000);
    recorder.setFormat("wav");
    recorder.setAudioCodec(avcodec.AV_CODEC_ID_PCM_S16LE);
    recorder.start();

    FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoInputStream);
    grabber.setSampleRate(8000);
    grabber.setOption("stimeout", String.valueOf(TimeUnit.MINUTES.toMicros(30L)));
    grabber.start();
    recorder.setAudioChannels(grabber.getAudioChannels());

    Frame frame;
    Long audioTime = grabber.getLengthInTime() / 1000 / 1000;

    while ((frame = grabber.grabSamples()) != null) {
        recorder.record(frame);
    }
    grabber.stop();
    recorder.close();

    ExtractAudioRes result = new ExtractAudioRes(audioOutputStream.toByteArray(), audioTime, audioOutputStream.size() / 1024);
    result.setFormat("wav");

    return result;
}

最後に、抽出された音声データをテキストに変換するためのコードです。ここではTencent CloudのASR APIを使用しています。

public String convertSpeechToText(byte[] audioData, String format) {
    log.info("Starting speech-to-text conversion");
    AsrClient client = new AsrClient(cred, "");
    SentenceRecognitionRequest request = new SentenceRecognitionRequest();
    request.setSourceType(1L);
    request.setVoiceFormat(format);
    request.setEngSerViceType("16k_zh");
    String base64EncodedData = BaseEncoding.base64().encode(audioData);
    request.setData(base64EncodedData);
    request.setDataLen((long) audioData.length);

    String text = "";
    try {
        SentenceRecognitionResponse response = client.SentenceRecognition(request);
        log.info("Speech-to-text result: {}", JSONUtil.toJsonStr(response));
        text = response.getResult();
        if (Strings.isNotBlank(text)) {
            return text;
        }
        return "No content";
    } catch (TencentCloudSDKException e) {
        log.error("Speech-to-text conversion failed: {}", e);
        throw new BusinessException(AUDIO_RECOGNIZE_ERROR.code(), "Speech-to-text conversion failed, please retry");
    }
}

長時間の音声データを処理する場合、以下のようなコードを使用します。

public String convertLongSpeechToText(byte[] audioData, String format) {
    log.info("Starting long speech-to-text conversion");
    Credential credential = Credential.builder()
            .secretId(AppConstant.Tencent.asrSecretId)
            .secretKey(AppConstant.Tencent.asrSecretKey)
            .build();
    String text = "";

    try {
        FlashRecognizer recognizer = SpeechClient.newFlashRecognizer(AppConstant.Tencent.arsAppId, credential);
        FlashRecognitionRequest request = FlashRecognitionRequest.initialize();
        request.setEngineType("16k_zh");
        request.setFirstChannelOnly(1);
        request.setVoiceFormat(format);
        request.setSpeakerDiarization(0);
        request.setFilterDirty(0);
        request.setFilterModal(0);
        request.setFilterPunc(0);
        request.setConvertNumMode(1);
        request.setWordInfo(1);

        FlashRecognitionResponse response = recognizer.recognize(request, audioData);

        if (SuccessCode.equals(response.getCode())) {
            text = response.getFlashResult().get(0).getText();
            return text;
        }
        log.info("Long speech-to-text conversion failed: {}", JSONUtil.toJsonStr(response));
        throw new BusinessException(AUDIO_RECOGNIZE_ERROR.code(), "Long speech-to-text conversion failed, please retry");
    } catch (Exception e) {
        log.error("Speech-to-text conversion failed: {}", e);
        throw new BusinessException(AUDIO_RECOGNIZE_ERROR.code(), "Speech-to-text conversion failed, please retry");
    }
}

public Boolean isLongAudio(AudioRecognitionReq req) {
    if (req.getAudioTime() == null || req.getAudioTime() >= AppConstant.Tencent.Max_Audio_Len || req.getAudioSize() >= AppConstant.Tencent.Max_Audio_Size) {
        return true;
    }
    return false;
}

これらのコードを使って、動画からテキストを抽出する機能を実装することができます。

タグ: JavaCV FFmpeg Tencent Cloud ASR 音声認識 動画処理

7月9日 17:31 投稿