media: reject voice duration by complete frames before encoding

This commit is contained in:
evgeny committed 2026-10-24 17:26:11 +02:00
1 parent 6f3d634c77
commit 68a7695d81
3 files changed
+15 -6

No files matched your search

+1 -1
View File
@@ -133,7 +133,7 @@ static void attachment_publish(struct attachment_send_req* req, int error) {
static void attachment_video_done(void* arg, int error, const struct video_info* info) {
struct attachment_send_req* req = arg;
if (!error && info && info->is_video && info->duration_ms > 0 && info->duration_ms <= 86400000 &&
if (!error && info && info->is_video && info->duration_ms > 0 && info->duration_ms <= ATTACHMENT_DURATION_MAX_MS &&
info->width > 0 && info->width <= 16384 && info->height > 0 && info->height <= 16384) {
req->info.duration_ms = (uint32_t)info->duration_ms;
req->info.width = (uint16_t)info->width; req->info.height = (uint16_t)info->height;
+12 -4
View File
@@ -12,8 +12,16 @@ int voice_file_encode(const int16_t* pcm, size_t count, int rate, int channels,
static const char levels[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (!pcm || !info || !path || (rate != 8000 && rate != 12000 && rate != 16000 && rate != 24000 && rate != 48000) ||
(channels != 1 && channels != 2) || preset < 0 || preset > 2) goto invalid;
size_t frame = (size_t)(rate / 50) * channels, samples = count / frame * frame;
if (samples < (size_t)rate * channels / 2 || samples / channels / rate > 86400) goto invalid;
size_t frame = (size_t)(rate / 50) * channels, frames = count / frame;
if (frames < 25 || frames > ATTACHMENT_DURATION_MAX_MS / 20) {
DEBUG_WARN(DEBUG_CATEGORY_MEDIA,
"voice_file: invalid duration count=%zu rate=%d channels=%d frames=%zu allowed_frames=25..%u",
count, rate, channels, frames, ATTACHMENT_DURATION_MAX_MS / 20);
return -1;
}
size_t samples = frames * frame;
DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "voice_file: encode count=%zu rate=%d channels=%d frames=%zu duration=%ums discarded=%zu",
count, rate, channels, frames, (uint32_t)(frames * 20), count - samples);
opus_codec_encoder_t* encoder = opus_codec_encoder_create(rate, channels);
if (!encoder) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice_file: encoder creation failed"); return -1; }
opus_codec_encoder_bitrate_set(encoder, bitrates[preset]);
@@ -34,7 +42,7 @@ int voice_file_encode(const int16_t* pcm, size_t count, int rate, int channels,
}
uint16_t end = 0;
if (fwrite(&end, 2, 1, file) != 1 || fflush(file)) goto done;
info->kind = ATTACHMENT_VOICE; info->duration_ms = (uint32_t)(samples / frame * 20);
info->kind = ATTACHMENT_VOICE; info->duration_ms = (uint32_t)(frames * 20);
info->width = info->height = 0;
for (size_t i = 0; i < 100; i++) {
size_t first = i * samples / 100, last = (i + 1) * samples / 100;
@@ -57,6 +65,6 @@ done:
} else DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "voice_file: prepared path=%s duration=%ums rate=%d channels=%d", path, info->duration_ms, rate, channels);
return error;
invalid:
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "voice_file: invalid/short recording count=%zu rate=%d channels=%d preset=%d", count, rate, channels, preset);
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "voice_file: invalid parameters count=%zu rate=%d channels=%d preset=%d", count, rate, channels, preset);
return -1;
}
+2 -1
View File
@@ -2,7 +2,8 @@
* PCM принадлежит вызывающему; encode заполняет duration/waveform по реально
* записанным кадрам. При ошибке неполный файл удаляется; возврат 0 / -1.
* count — число interleaved int16 отсчётов; rate — 8/12/16/24/48 kHz, channels — 1/2, preset — 0..2.
* Пишутся полные кадры по 20мс (хвост отбрасывается), минимум 500мс, максимум 24ч.
* Пишутся полные кадры по 20мс (хвост отбрасывается), минимум 500мс, максимум ATTACHMENT_DURATION_MAX_MS.
* Недопустимая длительность отвергается до создания encoder, открытия path и изменения info.
* name задаёт caller; encode устанавливает kind=VOICE и обнуляет width/height. */
#ifndef VOICE_FILE_H
#define VOICE_FILE_H