mstar.api_server.media_io#
Media decode/encode helpers shared by the native and OpenAI-compatible APIs.
Two directions:
Inbound — turn media referenced by an OpenAI-style request (
data:URLs,http(s)URLs, or base64 blobs) into files under the API server’supload_dir, somodel.load_image/load_audio/load_videocan read them by path. This is the same contract/generatealready uses for multipart uploads.Outbound — wrap raw model audio output (16-bit PCM, no container header) into a real audio container (WAV by default) and encode image bytes (PNG) as a
data:URL for OpenAI chat image output.
Only stdlib + numpy are required. mp3 / flac / ogg encoding is opt-in
and degrades to WAV when the optional soundfile backend is unavailable, so
the base install stays slim.
Functions
|
The |
|
|
|
Open the reference clip at |
|
Refuse a file rate outside |
|
Decode an audio file to a float32 mono numpy waveform at |
|
FFmpeg (torchcodec) decode of |
|
Map a MIME type to one of our modality strings (image/audio/video). |
|
Mux an H.264 mp4 and raw interleaved 16-bit PCM into one mp4 with an AAC audio track (stream-copies the video). |
|
Encode raw 16-bit PCM into |
|
Wrap raw little-endian 16-bit PCM (the model's audio output) into a WAV blob. |
|
Encode PNG image bytes (the model's image output) as a data URL. |
|
libsndfile decode of |
|
Delete a request's files under |
|
Floats in torchaudio's default sinc kernel resampling |
|
Resolve a media reference from a request: a data URL, or an http(s) URL when remote fetch is allowed. |
|
Persist a bare base64 blob with a known |
|
Persist bare base64 that passes |
|
Persist a |
|
Download an |
|
|
|
Cut a waveform into consecutive windows of at most |
|
|
|
A 44-byte WAV header with streaming (unknown-length) size fields. |
|
Nominal end of the window starting at |
|
Float waveform -> 16-bit PCM WAV file at |
Classes
|
Resample a stream that arrives in pieces of any size ( |
Exceptions
Audio a decoder opened and refuses (too long, or an unsupported rate): callers re-raise it rather than fall back to another decoder. |
|
|
Audio that decodes past the limit, whatever its header declares. |
A clip that opens as audio but runs past |
- exception mstar.api_server.media_io.AudioRefusedError[source]#
Bases:
ValueErrorAudio a decoder opened and refuses (too long, or an unsupported rate): callers re-raise it rather than fall back to another decoder.
- exception mstar.api_server.media_io.AudioTooLongError(max_seconds)[source]#
Bases:
AudioRefusedErrorAudio that decodes past the limit, whatever its header declares.
- Parameters:
max_seconds (float)
- status_code = 413#
- exception mstar.api_server.media_io.RefAudioTooLongError[source]#
Bases:
ValueErrorA clip that opens as audio but runs past
MAX_REF_AUDIO_SECONDS.
- class mstar.api_server.media_io.StreamResampler(rate_in, rate_out, half_width=48, beta=10.0, rolloff=0.95)[source]#
Bases:
objectResample a stream that arrives in pieces of any size (
push), with the same output however it was split. A Kaiser-windowed sinc lowpass at the lower Nyquist, applied polyphase: outputkis centered on input timek * rate_in / rate_out, so timing is kept exactly. The passband is flat to 0.1 dB up to 0.9 of the lower Nyquist and 3 dB down at 0.94 (7.2 and 7.5 kHz at 24 to 16 kHz), close to what a 16 kHz recording holds; anything above that Nyquist, which would fold back, is down 46 dB or more, and 100 dB from 1.06 of it on. Each output waits for half a kernel of input past its center (72 samples, 3 ms, at 24 to 16 kHz);flushemits the rest as if the input went on as silence,ceil(n_in * rate_out / rate_in)samples in all, and starts over. The kernel has2 * half_width * max(up, down) + 1taps for the reduced ratioup/down, so callers bound the rates.
- mstar.api_server.media_io.audio_formats(stream=False, sample_rate=None)[source]#
The
response_formatvalues this frontend can produce.A stream carries an open-ended WAV or bare PCM, so only those two; the compressed containers need the optional
soundfile(theaudioextra), and Opus also needs one of its native sample rates whensample_rateis given.
- mstar.api_server.media_io.check_audio_format(fmt, stream=False, sample_rate=None)[source]#
fmtlower-cased (wavwhen unset); ValueError when it cannot be produced.
- mstar.api_server.media_io.check_ref_audio(path, decoder)[source]#
Open the reference clip at
paththe way the model’sload_audiowill; on failure delete it and raise ValueError.decoderis the library thatload_audiouses:"soundfile","torchcodec", or"soundfile+torchcodec"for a loader that tries libsndfile first and FFmpeg for what it cannot open, asModel.load_audiodoes. torchcodec decodes the clip, not just its header: some FFmpeg builds parse a container header (MAT4, MAT5) they cannot decode. A clip whose header rate is belowMIN_REF_AUDIO_SAMPLE_RATE, or whose header duration is overMAX_REF_AUDIO_SECONDS, is refused before any decode; the decode itself stops just pastMAX_REF_AUDIO_SECONDS, so a header that hides or understates the length cannot make it unbounded.
- mstar.api_server.media_io.check_resample_rate(rate, target)[source]#
Refuse a file rate outside
1..MAX_SAMPLE_RATEHz or whose resampling totargetwould cost more thanMAX_RESAMPLE_KERNEL(every real rate, pull-down rates included, passes).
- mstar.api_server.media_io.decode_audio(path, sample_rate=16000, max_seconds=MAX_AUDIO_SECONDS)[source]#
Decode an audio file to a float32 mono numpy waveform at
sample_rate, refused withAudioTooLongErrorpastmax_seconds.The same decode as a model’s own uploads (
load_speech_file): a file neither libsndfile nor FFmpeg reads raisesValueError(HTTP 400), while a missing FFmpeg stays the server’s error.
- mstar.api_server.media_io.decode_torchcodec_capped(path, sample_rate, max_seconds=MAX_AUDIO_SECONDS)[source]#
FFmpeg (torchcodec) decode of
path: a float32 mono tensor atsample_rate, the same samplesget_all_samples()returns.The decode stops just past
max_secondsof play time, and the audio is refused withAudioTooLongErrorwhen it plays longer or holds more samples than that. The decoder resamples every frame tosample_rate, so what is counted is decoded output, not the rate or duration the container declares.
- mstar.api_server.media_io.modality_from_mime(mime)[source]#
Map a MIME type to one of our modality strings (image/audio/video).
- mstar.api_server.media_io.mux_mp4_with_pcm16(video_mp4, pcm, sample_rate, num_channels=2, video_fps=None)[source]#
Mux an H.264 mp4 and raw interleaved 16-bit PCM into one mp4 with an AAC audio track (stream-copies the video).
video_fpsis the true frame rate of the content: when it differs from the container’s rate the video timestamps are rescaled (no re-encode) so playback runs at the real rate and stays in sync with the audio track. Requires theffmpegbinary; raises on failure — callers fall back to the video-only mp4.
- mstar.api_server.media_io.pcm16_to_container(pcm, sample_rate, fmt='wav')[source]#
Encode raw 16-bit PCM into
fmt. Returns(bytes, mime_type).wavandpcmuse the stdlib (the bytes are already PCM_16); the compressed formats use the optionalsoundfile. A format this server cannot produce raises ValueError (seecheck_audio_format()) rather than coming back as WAV under another name.
- mstar.api_server.media_io.pcm16_to_wav_bytes(pcm, sample_rate, num_channels=1)[source]#
Wrap raw little-endian 16-bit PCM (the model’s audio output) into a WAV blob.
- mstar.api_server.media_io.png_to_data_url(png_bytes)[source]#
Encode PNG image bytes (the model’s image output) as a data URL.
- mstar.api_server.media_io.read_soundfile_capped(path, max_seconds=MAX_AUDIO_SECONDS)[source]#
libsndfile decode of
path: float32 mono at the file’s own rate.Reads in blocks and counts the frames it decodes, so a header that hides or understates the length cannot make the read unbounded; past
max_secondsit raisesAudioTooLongError. A rate outside1..MAX_SAMPLE_RATEis refused (AudioRefusedError) before any read. A container libsndfile cannot read raises soundfile’s own error.
- mstar.api_server.media_io.remove_uploads(file_paths, upload_dir)[source]#
Delete a request’s files under
upload_dirnow. A path elsewhere is left alone: no route puts one infile_pathstoday, and a file the server did not save is never the request’s to delete.
- mstar.api_server.media_io.resample_kernel_size(rate, target)[source]#
Floats in torchaudio’s default sinc kernel resampling
ratetotarget.
- mstar.api_server.media_io.resolve_media_ref(ref, upload_dir, *, allow_remote=False)[source]#
Resolve a media reference from a request: a data URL, or an http(s) URL when remote fetch is allowed. Returns
(modality, path).A request cannot name a file on the server, not even one under
upload_dir: plain paths and other URL schemes are refused without accessing client-named server files, so a caller can neither read files nor probe for them.
- mstar.api_server.media_io.save_base64(b64, fmt, modality_hint, upload_dir)[source]#
Persist a bare base64 blob with a known
fmt(e.g."wav").
- mstar.api_server.media_io.save_base64_audio(b64, upload_dir, decoder)[source]#
Persist bare base64 that passes
check_ref_audio(); return its path, or None (leaving nothing behind) when it is not base64 or not loadable audio.A path such as
/etc/passwdis valid base64 too, so the alphabet cannot tell them apart; the decoder can. A clip that is audio but too long raisesRefAudioTooLongError.
- mstar.api_server.media_io.save_data_url(data_url, upload_dir)[source]#
Persist a
data:<mime>;base64,<payload>URL. Returns (modality, path).
- mstar.api_server.media_io.save_remote_url(url, upload_dir, timeout=30.0)[source]#
Download an
http(s)URL intoupload_dir. Returns (modality, path).Note: fetching arbitrary URLs has SSRF surface. Callers exposing this publicly should allowlist hosts or disable remote fetch (data-URL only).
- mstar.api_server.media_io.schedule_upload_cleanup(file_paths, upload_dir)[source]#
remove_uploads()afterUPLOAD_CLEANUP_DELAY_S, for a request that was submitted and may not have been read yet.
- mstar.api_server.media_io.split_windows(audio, window_seconds, sample_rate=16000, search_seconds=0.0, frame_seconds=0.02, balanced=False)[source]#
Cut a waveform into consecutive windows of at most
window_seconds; concatenating them gives the input back sample for sample.With
search_secondsa cut is moved back from its nominal boundary to the end of the quietestframe_secondsframe within that span (the last such frame on a tie, so silence cuts at the boundary): the cut lands in a pause rather than on a word when there is one to find.balancedplaces the nominal boundaries aswindow_stop()does.
- mstar.api_server.media_io.torchcodec_samples_capped(path, max_seconds=MAX_AUDIO_SECONDS, **decoder_args)[source]#
AudioDecoder(path, **decoder_args)’s samples from the stream’s first frame, asget_all_samples()returns them, decoding just pastmax_secondsof play time; refused withAudioTooLongErrorwhen the audio plays longer or holds more samples than that.
- mstar.api_server.media_io.wav_stream_header(sample_rate, num_channels=1, bits=16)[source]#
A 44-byte WAV header with streaming (unknown-length) size fields.
Used to stream TTS audio over a single HTTP response: emit this header, then 16-bit PCM frames as they arrive. The 0xFFFFFFFF placeholders signal an open-ended stream, which players and the OpenAI client’s
stream_to_filehandle.