Video To Text · 5 min read · July 15, 2026

How to Convert Video to Text in Python

Learn how to extract a transcript from a video in Python using Whisper, Faster-Whisper, FFmpeg, MoviePy, and Vosk. Includes step-by-step tutorials, complete code examples, subtitle generation (SRT/VTT), timestamps.

HA

Hassan Agmir

Author at Filenewer

Share:
How to Convert Video to Text in Python

Extracting a transcript from a video in Python is one of those tasks that looks simple at first, then quickly turns into a small pipeline: get the audio, clean it up, send it into a speech-to-text engine, and format the result into something useful. The good news is that Python gives you several solid ways to do it, whether you want a quick local solution, a production-ready transcription service, or a high-accuracy workflow for long videos.

In this article, you will learn how to extract a transcript from a video in Python step by step. We will cover multiple approaches, from the simplest setup using OpenAI Whisper to offline options like Vosk, along with audio extraction, subtitle formatting, timestamp handling, and practical code examples you can adapt to your own projects.


What you will build

By the end of this guide, you will be able to:

  • Load a video file in Python

  • Extract its audio track

  • Transcribe speech into text

  • Generate plain text, SRT subtitles, or JSON output

  • Work with local models or cloud APIs

  • Improve accuracy with preprocessing

  • Handle long videos efficiently


Why extract transcripts from videos?

A transcript makes a video searchable, reusable, and more accessible. Once you have text, you can:

  • Add subtitles to social videos

  • Search inside recorded meetings

  • Build content summaries

  • Index lectures for learning platforms

  • Repurpose videos into blog posts

  • Improve SEO for video-based content

  • Support accessibility and multilingual workflows

For developers, transcription is also a building block. It can power caption generators, note-taking apps, podcast tools, educational platforms, and content extraction services.


The basic pipeline

Almost every Python transcription workflow follows the same stages:

  1. Read the video

  2. Extract audio from the video

  3. Convert audio to a speech-friendly format

  4. Send audio to a speech-to-text model or API

  5. Post-process the transcript

  6. Export it in the desired format

The exact tools may change, but the pipeline is the same.


Option 1: The simplest path with Whisper

If you want a strong balance between accuracy and developer friendliness, Whisper is one of the best options. It can run locally and works well across different accents and noisy environments.

There are two common Whisper options:

  • openai-whisper for local transcription

  • faster-whisper for faster inference and lower resource use

Both are excellent, but faster-whisper is often a better choice for production-like workloads.


Installing the required tools

Before you begin, install FFmpeg. It is the standard tool for working with video and audio files.

Install Python packages

pip install openai-whisper
pip install faster-whisper
pip install moviepy
pip install pydub
pip install vosk
pip install ffmpeg-python

Install FFmpeg

On Windows, download FFmpeg and add it to your PATH.

On macOS:

brew install ffmpeg

On Ubuntu/Debian:

sudo apt update
sudo apt install ffmpeg

Check the installation:

ffmpeg -version

Method 1: Extract transcript from a video using Whisper

This is the most practical starting point. We will first extract audio from the video, then transcribe it.

Step 1: Extract audio from the video

You can use moviepy to extract the audio track.

from moviepy.editor import VideoFileClip


def extract_audio(video_path: str, audio_path: str) -> None:
    video = VideoFileClip(video_path)
    audio = video.audio
    audio.write_audiofile(audio_path, codec="pcm_s16le")
    audio.close()
    video.close()


extract_audio("input_video.mp4", "output_audio.wav")

This creates a WAV file, which is easy for speech recognition tools to process.


Step 2: Transcribe audio with Whisper

import whisper


def transcribe_audio(audio_path: str, model_size: str = "base") -> dict:
    model = whisper.load_model(model_size)
    result = model.transcribe(audio_path)
    return result


result = transcribe_audio("output_audio.wav")
print(result["text"])

Step 3: Save transcript to a text file

from pathlib import Path


def save_transcript_text(result: dict, output_path: str) -> None:
    text = result.get("text", "").strip()
    Path(output_path).write_text(text, encoding="utf-8")


save_transcript_text(result, "transcript.txt")

Method 2: Transcribe video directly with faster-whisper

If you want better speed, faster-whisper is a great option. It is efficient and works well for larger files.

Example

from faster_whisper import WhisperModel


def transcribe_with_faster_whisper(audio_path: str, model_size: str = "small") -> str:
    model = WhisperModel(model_size, device="cpu", compute_type="int8")
    segments, info = model.transcribe(audio_path, beam_size=5)

    transcript_parts = []
    for segment in segments:
        transcript_parts.append(segment.text)

    return " ".join(transcript_parts)


transcript = transcribe_with_faster_whisper("output_audio.wav")
print(transcript)

Why faster-whisper is useful

  • Faster inference than standard Whisper in many setups

  • Good for long files

  • Lower memory usage options

  • Flexible CPU/GPU configuration


Method 3: Use FFmpeg for audio extraction without MoviePy

Sometimes you do not need a video library at all. FFmpeg can extract audio directly and often more reliably.

import subprocess


def extract_audio_ffmpeg(video_path: str, audio_path: str) -> None:
    command = [
        "ffmpeg",
        "-y",
        "-i", video_path,
        "-vn",
        "-acodec", "pcm_s16le",
        "-ar", "16000",
        "-ac", "1",
        audio_path,
    ]
    subprocess.run(command, check=True)


extract_audio_ffmpeg("input_video.mp4", "audio.wav")

This method is often preferred because it is fast, simple, and dependable.

Why use these FFmpeg flags?

  • -vn: no video

  • -acodec pcm_s16le: uncompressed WAV audio

  • -ar 16000: 16 kHz sample rate, good for speech tasks

  • -ac 1: mono audio


A complete end-to-end example

Here is a simple but complete script that:

  • extracts audio from a video

  • transcribes it

  • saves the transcript

import subprocess
from pathlib import Path
import whisper


def extract_audio_ffmpeg(video_path: str, audio_path: str) -> None:
    command = [
        "ffmpeg",
        "-y",
        "-i", video_path,
        "-vn",
        "-acodec", "pcm_s16le",
        "-ar", "16000",
        "-ac", "1",
        audio_path,
    ]
    subprocess.run(command, check=True)


def transcribe_audio(audio_path: str, model_size: str = "base") -> dict:
    model = whisper.load_model(model_size)
    return model.transcribe(audio_path)


def save_text(result: dict, output_txt: str) -> None:
    text = result.get("text", "").strip()
    Path(output_txt).write_text(text, encoding="utf-8")


def video_to_transcript(video_path: str, transcript_path: str, model_size: str = "base") -> None:
    audio_path = "temp_audio.wav"
    extract_audio_ffmpeg(video_path, audio_path)
    result = transcribe_audio(audio_path, model_size=model_size)
    save_text(result, transcript_path)


video_to_transcript("input_video.mp4", "transcript.txt", model_size="base")

Getting timestamps for subtitles

Plain text transcripts are useful, but sometimes you need subtitle timing. Whisper can return segments with timestamps.

Example with segments

import whisper


model = whisper.load_model("base")
result = model.transcribe("audio.wav")

for segment in result["segments"]:
    start = segment["start"]
    end = segment["end"]
    text = segment["text"].strip()
    print(f"{start:.2f} --> {end:.2f} : {text}")

This output is the foundation for SRT or VTT subtitles.


Convert transcript to SRT

SubRip Subtitle format uses numbered blocks and time ranges.

SRT writer example

def format_srt_time(seconds: float) -> str:
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    secs = int(seconds % 60)
    milliseconds = int((seconds - int(seconds)) * 1000)
    return f"{hours:02}:{minutes:02}:{secs:02},{milliseconds:03}"


def segments_to_srt(segments: list) -> str:
    srt_lines = []
    for i, segment in enumerate(segments, start=1):
        start = format_srt_time(segment["start"])
        end = format_srt_time(segment["end"])
        text = segment["text"].strip()
        srt_lines.append(f"{i}\n{start} --> {end}\n{text}\n")
    return "\n".join(srt_lines)


import whisper

model = whisper.load_model("base")
result = model.transcribe("audio.wav")
srt_content = segments_to_srt(result["segments"])

with open("output.srt", "w", encoding="utf-8") as f:
    f.write(srt_content)

Convert transcript to VTT

WebVTT is useful for browsers and modern video players.

def format_vtt_time(seconds: float) -> str:
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    secs = int(seconds % 60)
    milliseconds = int((seconds - int(seconds)) * 1000)
    return f"{hours:02}:{minutes:02}:{secs:02}.{milliseconds:03}"


def segments_to_vtt(segments: list) -> str:
    lines = ["WEBVTT", ""]
    for segment in segments:
        start = format_vtt_time(segment["start"])
        end = format_vtt_time(segment["end"])
        text = segment["text"].strip()
        lines.append(f"{start} --> {end}")
        lines.append(text)
        lines.append("")
    return "\n".join(lines)

Offline transcription with Vosk

If you need a fully offline workflow and want lightweight speech recognition, Vosk is a strong choice.

Install Vosk

pip install vosk

You also need a model from the Vosk website. After downloading it, place it in a folder such as vosk-model-small-en-us-0.15.

Transcribe audio with Vosk

import wave
import json
from vosk import Model, KaldiRecognizer


def transcribe_with_vosk(wav_path: str, model_path: str) -> str:
    wf = wave.open(wav_path, "rb")
    model = Model(model_path)
    recognizer = KaldiRecognizer(model, wf.getframerate())

    transcript_parts = []

    while True:
        data = wf.readframes(4000)
        if len(data) == 0:
            break
        if recognizer.AcceptWaveform(data):
            result = json.loads(recognizer.Result())
            transcript_parts.append(result.get("text", ""))

    final_result = json.loads(recognizer.FinalResult())
    transcript_parts.append(final_result.get("text", ""))

    return " ".join(part for part in transcript_parts if part).strip()

When to use Vosk

Use Vosk when you need:

  • offline transcription

  • lower memory usage

  • streaming recognition

  • simple deployment on limited hardware

It may not match Whisper in accuracy, but it can be very practical.


Handling long videos

Long videos introduce new problems:

  • large file sizes

  • memory pressure

  • slow processing

  • repeated silence

  • noisy sections

A better approach is to split the audio into chunks.

Chunking audio with pydub

from pydub import AudioSegment
from pathlib import Path


def split_audio(audio_path: str, chunk_length_ms: int = 60_000, output_dir: str = "chunks") -> list[str]:
    audio = AudioSegment.from_file(audio_path)
    Path(output_dir).mkdir(parents=True, exist_ok=True)

    chunk_paths = []
    for i in range(0, len(audio), chunk_length_ms):
        chunk = audio[i:i + chunk_length_ms]
        chunk_path = Path(output_dir) / f"chunk_{i // chunk_length_ms:04}.wav"
        chunk.export(chunk_path, format="wav")
        chunk_paths.append(str(chunk_path))

    return chunk_paths

Transcribe each chunk

import whisper


def transcribe_chunks(chunk_paths: list[str], model_size: str = "base") -> str:
    model = whisper.load_model(model_size)
    all_text = []

    for chunk_path in chunk_paths:
        result = model.transcribe(chunk_path)
        text = result.get("text", "").strip()
        if text:
            all_text.append(text)

    return "\n".join(all_text)

This technique is helpful for very long lectures, webinars, and interviews.


Improving transcription accuracy

The quality of the transcript depends heavily on the audio.

1. Use a clean audio source

If possible, start from the best possible source file. Avoid heavily compressed or distorted audio.

2. Normalize and convert audio

Speech models often perform better on mono, 16 kHz WAV audio.

3. Remove silence

Silence removal can speed up transcription and reduce empty results.

4. Reduce background noise

You can preprocess audio with noise reduction libraries or filters.

5. Choose the right model size

With Whisper:

  • tiny is fastest but least accurate

  • base is a decent default

  • small and medium improve quality

  • large gives stronger accuracy but uses more resources

6. Use language hints

If you know the language, pass it to the model. That can improve results.

result = model.transcribe("audio.wav", language="en")

Transcribing a YouTube video in Python

Many people ask how to extract transcripts from videos on YouTube. The workflow is similar, but first you need the media file or the audio stream.

One common approach is:

  1. Download the video or audio

  2. Extract the audio track

  3. Send it to a transcription engine

Example using yt-dlp

pip install yt-dlp
import os
import subprocess


def download_youtube_audio(url: str, output_dir: str = "downloads") -> str:
    os.makedirs(output_dir, exist_ok=True)
    output_template = os.path.join(output_dir, "%(title)s.%(ext)s")

    command = [
        "yt-dlp",
        "-f", "bestaudio",
        "-o", output_template,
        url,
    ]
    subprocess.run(command, check=True)

    # In real projects, inspect the downloaded filename more carefully.
    return output_dir

After downloading, use FFmpeg or your transcription tool of choice.


Creating a reusable Python class

A class can make your code cleaner and easier to reuse.

import subprocess
from pathlib import Path
import whisper


class VideoTranscriptExtractor:
    def __init__(self, model_size: str = "base"):
        self.model = whisper.load_model(model_size)

    def extract_audio(self, video_path: str, audio_path: str) -> None:
        command = [
            "ffmpeg",
            "-y",
            "-i", video_path,
            "-vn",
            "-acodec", "pcm_s16le",
            "-ar", "16000",
            "-ac", "1",
            audio_path,
        ]
        subprocess.run(command, check=True)

    def transcribe(self, audio_path: str) -> dict:
        return self.model.transcribe(audio_path)

    def video_to_text(self, video_path: str, output_txt: str) -> str:
        temp_audio = "temp_audio.wav"
        self.extract_audio(video_path, temp_audio)
        result = self.transcribe(temp_audio)
        text = result.get("text", "").strip()
        Path(output_txt).write_text(text, encoding="utf-8")
        return text


extractor = VideoTranscriptExtractor(model_size="base")
transcript = extractor.video_to_text("input_video.mp4", "transcript.txt")
print(transcript)

Returning JSON output

For APIs and applications, JSON is often better than plain text.

import json
import whisper


model = whisper.load_model("base")
result = model.transcribe("audio.wav")

with open("transcript.json", "w", encoding="utf-8") as f:
    json.dump(result, f, ensure_ascii=False, indent=2)

This gives you:

  • transcript text

  • segments

  • timestamps

  • language detection

  • metadata for downstream processing


Building an API endpoint for transcription

If you are building a web service, you can wrap the logic inside FastAPI or Django REST Framework.

Example FastAPI endpoint

from fastapi import FastAPI, UploadFile, File
import shutil
import whisper
import subprocess
from pathlib import Path

app = FastAPI()
model = whisper.load_model("base")


@app.post("/transcribe")
async def transcribe_video(file: UploadFile = File(...)):
    upload_path = Path("uploads") / file.filename
    upload_path.parent.mkdir(exist_ok=True)

    with open(upload_path, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)

    audio_path = upload_path.with_suffix(".wav")

    subprocess.run([
        "ffmpeg", "-y", "-i", str(upload_path),
        "-vn", "-acodec", "pcm_s16le", "-ar", "16000", "-ac", "1", str(audio_path)
    ], check=True)

    result = model.transcribe(str(audio_path))
    return {
        "text": result["text"],
        "segments": result["segments"],
        "language": result.get("language")
    }

This is the foundation of a transcript extraction API.


Best practices for production

When transcription becomes a real feature, keep these points in mind:

Validate input files

Check file type, file size, duration, and upload errors.

Use temporary storage carefully

Clean up audio files after processing to avoid wasting disk space.

Handle long-running jobs asynchronously

Use Celery, RQ, or a background worker if transcription takes time.

Protect your API

Limit uploads, authenticate users, and guard against abuse.

Keep transcripts versioned

If you improve your model later, storing transcript versions can help.

Store speaker metadata when possible

For meeting transcription, speaker diarization may be important.


Common mistakes

Forgetting to extract audio first

Many speech models work best with audio, not raw video.

Using compressed audio with poor quality

Bad source audio means bad transcripts.

Ignoring timestamps

Timestamps are essential if you need subtitles or searchable playback.

Processing huge files in one go

Chunking is often safer for long recordings.

Not cleaning up temp files

Temporary audio files can quickly fill disk space.


Comparing the main approaches

Whisper

Best for strong accuracy and general-purpose transcription.

faster-whisper

Best for speed and efficiency.

Vosk

Best for offline and lightweight deployment.

Cloud APIs

Best when you need managed infrastructure and do not want to maintain models locally.

Each method has trade-offs. The right choice depends on cost, privacy, performance, and accuracy.


A practical recommendation

If you are building a real Python project today, this is a good decision path:

  • Use FFmpeg to extract audio

  • Use faster-whisper for local transcription

  • Use Whisper if you want simple, reliable quality

  • Use Vosk if everything must stay offline

  • Return JSON when building an API

  • Export SRT when you need subtitles

That combination covers most use cases.


Final example: video to transcript function

Here is a neat utility function you can reuse directly.

import subprocess
from pathlib import Path
import whisper


def video_to_transcript(video_path: str, output_txt: str = "transcript.txt", model_size: str = "base") -> str:
    video_path = str(video_path)
    output_txt = str(output_txt)
    audio_path = Path(output_txt).with_suffix(".wav")

    subprocess.run([
        "ffmpeg", "-y", "-i", video_path,
        "-vn", "-acodec", "pcm_s16le", "-ar", "16000", "-ac", "1",
        str(audio_path)
    ], check=True)

    model = whisper.load_model(model_size)
    result = model.transcribe(str(audio_path))
    text = result.get("text", "").strip()

    Path(output_txt).write_text(text, encoding="utf-8")
    return text


if __name__ == "__main__":
    transcript = video_to_transcript("input_video.mp4", "transcript.txt", model_size="base")
    print(transcript)

Conclusion

Extracting transcripts from videos in Python is a very achievable task once you understand the pipeline. The video itself is only the starting point. The real work happens when you turn the audio into a clean, usable transcript with a model like Whisper, faster-whisper, or Vosk.

Start with FFmpeg for audio extraction, use a transcription engine that matches your needs, then format the output for your use case. Whether you are building subtitles, search tools, educational software, or a content automation system, this workflow gives you a reliable foundation.

The best part is that you can begin with a very small script and grow it into a complete production system later.

HA

Hassan Agmir

Author · Filenewer

Writing about file tools and automation at Filenewer.

Try It Free

Process your files right now

No account needed · Fast & secure · 100% free

Browse All Tools