mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 11:51:49 +09:00
TAV: different filter for FPS up/downconversion
This commit is contained in:
@@ -401,18 +401,35 @@ static int get_video_info(const char *input_file, int *width, int *height,
|
||||
* - Filtergraph: scale/crop to full size, then tinterlace weave halves
|
||||
* framerate, then separatefields restores framerate at half height
|
||||
*
|
||||
* When target_fps_num > 0:
|
||||
* - Applies fps filter at the start to convert to target framerate
|
||||
* Framerate conversion:
|
||||
* - If target_fps > source_fps: uses minterpolate for motion interpolation
|
||||
* - If target_fps < source_fps: uses fps filter for frame dropping
|
||||
* - If target_fps == source_fps: no fps filter applied
|
||||
*/
|
||||
static FILE* open_ffmpeg_pipe(const char *input_file, int width, int height,
|
||||
int interlaced, int full_height,
|
||||
int target_fps_num, int target_fps_den) {
|
||||
int target_fps_num, int target_fps_den,
|
||||
int source_fps_num, int source_fps_den) {
|
||||
char cmd[MAX_PATH * 2];
|
||||
char fps_filter[64] = "";
|
||||
char fps_filter[128] = "";
|
||||
|
||||
// Build fps filter string if conversion is requested (applied first)
|
||||
if (target_fps_num > 0 && target_fps_den > 0) {
|
||||
snprintf(fps_filter, sizeof(fps_filter), "fps=%d/%d,", target_fps_num, target_fps_den);
|
||||
if (target_fps_num > 0 && target_fps_den > 0 &&
|
||||
source_fps_num > 0 && source_fps_den > 0) {
|
||||
// Compare framerates: target/1 vs source/1 -> target * source_den vs source * target_den
|
||||
double target_rate = (double)target_fps_num / (double)source_fps_den;
|
||||
double source_rate = (double)source_fps_num / (double)target_fps_den;
|
||||
|
||||
if (target_rate > source_rate) {
|
||||
// Upsampling: use motion interpolation
|
||||
snprintf(fps_filter, sizeof(fps_filter), "minterpolate=fps=%d/%d,",
|
||||
target_fps_num, target_fps_den);
|
||||
} else if (target_rate < source_rate) {
|
||||
// Downsampling: use fps filter
|
||||
snprintf(fps_filter, sizeof(fps_filter), "fps=%d/%d,",
|
||||
target_fps_num, target_fps_den);
|
||||
}
|
||||
// If equal, fps_filter remains empty (no conversion needed)
|
||||
}
|
||||
|
||||
if (interlaced) {
|
||||
@@ -1439,7 +1456,9 @@ static int encode_video_mt(cli_context_t *cli) {
|
||||
cli->interlaced,
|
||||
cli->header_height,
|
||||
cli->target_fps_num,
|
||||
cli->target_fps_den);
|
||||
cli->target_fps_den,
|
||||
cli->original_fps_num,
|
||||
cli->original_fps_den);
|
||||
if (!cli->ffmpeg_pipe) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1905,7 +1924,9 @@ static int encode_video(cli_context_t *cli) {
|
||||
cli->interlaced,
|
||||
cli->header_height,
|
||||
cli->target_fps_num,
|
||||
cli->target_fps_den);
|
||||
cli->target_fps_den,
|
||||
cli->original_fps_num,
|
||||
cli->original_fps_den);
|
||||
if (!cli->ffmpeg_pipe) {
|
||||
return -1;
|
||||
}
|
||||
@@ -2484,7 +2505,8 @@ int main(int argc, char *argv[]) {
|
||||
fprintf(stderr, "Error: Invalid fps format. Use NUM or NUM/DEN\n");
|
||||
return 1;
|
||||
}
|
||||
need_probe_fps = 0;
|
||||
// Keep need_probe_fps = 1 so we always probe source fps
|
||||
// (needed for minterpolate vs fps filter decision)
|
||||
cli.target_fps_num = num;
|
||||
cli.target_fps_den = den;
|
||||
cli.enc_params.fps_num = num;
|
||||
@@ -2647,11 +2669,13 @@ int main(int argc, char *argv[]) {
|
||||
printf(" Resolution: %dx%d\n", cli.original_width, cli.original_height);
|
||||
}
|
||||
|
||||
// Always print source framerate
|
||||
printf(" Framerate: %d/%d\n", cli.original_fps_num, cli.original_fps_den);
|
||||
|
||||
// Use probed framerate if not specified by -f
|
||||
if (need_probe_fps) {
|
||||
if (cli.target_fps_num == 0) {
|
||||
cli.enc_params.fps_num = cli.original_fps_num;
|
||||
cli.enc_params.fps_den = cli.original_fps_den;
|
||||
printf(" Framerate: %d/%d\n", cli.original_fps_num, cli.original_fps_den);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2671,11 +2695,19 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// Report fps conversion if enabled
|
||||
if (cli.target_fps_num > 0 && cli.original_fps_num > 0) {
|
||||
if (cli.target_fps_num != cli.original_fps_num || cli.target_fps_den != cli.original_fps_den) {
|
||||
printf("Framerate conversion: %d/%d -> %d/%d\n",
|
||||
long long target_rate = (long long)cli.target_fps_num * cli.original_fps_den;
|
||||
long long source_rate = (long long)cli.original_fps_num * cli.target_fps_den;
|
||||
|
||||
if (target_rate > source_rate) {
|
||||
printf("Framerate conversion: %d/%d -> %d/%d (minterpolate)\n",
|
||||
cli.original_fps_num, cli.original_fps_den,
|
||||
cli.target_fps_num, cli.target_fps_den);
|
||||
} else if (target_rate < source_rate) {
|
||||
printf("Framerate conversion: %d/%d -> %d/%d (fps)\n",
|
||||
cli.original_fps_num, cli.original_fps_den,
|
||||
cli.target_fps_num, cli.target_fps_den);
|
||||
}
|
||||
// If equal, no message needed (no conversion)
|
||||
} else if (cli.target_fps_num > 0) {
|
||||
printf("Output framerate: %d/%d\n", cli.target_fps_num, cli.target_fps_den);
|
||||
}
|
||||
|
||||
@@ -180,6 +180,8 @@ typedef struct {
|
||||
int fps_den;
|
||||
int target_fps_num; // Target output framerate numerator (0 = no conversion)
|
||||
int target_fps_den; // Target output framerate denominator
|
||||
int original_fps_num; // Source framerate (always probed)
|
||||
int original_fps_den;
|
||||
int is_interlaced;
|
||||
int is_pal;
|
||||
int quality_index;
|
||||
@@ -435,10 +437,23 @@ static FILE *spawn_ffmpeg_video(dt_encoder_t *enc, pid_t *pid) {
|
||||
snprintf(video_size, sizeof(video_size), "%dx%d", enc->width, enc->height);
|
||||
|
||||
// Build fps filter prefix if conversion is requested
|
||||
char fps_filter[64] = "";
|
||||
if (enc->target_fps_num > 0 && enc->target_fps_den > 0) {
|
||||
snprintf(fps_filter, sizeof(fps_filter), "fps=%d/%d,",
|
||||
enc->target_fps_num, enc->target_fps_den);
|
||||
char fps_filter[128] = "";
|
||||
if (enc->target_fps_num > 0 && enc->target_fps_den > 0 &&
|
||||
enc->original_fps_num > 0 && enc->original_fps_den > 0) {
|
||||
// Compare framerates
|
||||
long long target_rate = (long long)enc->target_fps_num * enc->original_fps_den;
|
||||
long long source_rate = (long long)enc->original_fps_num * enc->target_fps_den;
|
||||
|
||||
if (target_rate > source_rate) {
|
||||
// Upsampling: use motion interpolation
|
||||
snprintf(fps_filter, sizeof(fps_filter), "minterpolate=fps=%d/%d,",
|
||||
enc->target_fps_num, enc->target_fps_den);
|
||||
} else if (target_rate < source_rate) {
|
||||
// Downsampling: use fps filter
|
||||
snprintf(fps_filter, sizeof(fps_filter), "fps=%d/%d,",
|
||||
enc->target_fps_num, enc->target_fps_den);
|
||||
}
|
||||
// If equal, fps_filter remains empty
|
||||
}
|
||||
|
||||
// Use same filtergraph as reference TAV encoder
|
||||
@@ -1390,8 +1405,9 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Probe input file for framerate
|
||||
int original_fps_num = 24, original_fps_den = 1;
|
||||
// Probe input file for framerate (always probe to get original fps)
|
||||
enc.original_fps_num = 24;
|
||||
enc.original_fps_den = 1;
|
||||
char probe_cmd[4096];
|
||||
snprintf(probe_cmd, sizeof(probe_cmd),
|
||||
"ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=nw=1:nk=1 '%s'",
|
||||
@@ -1401,9 +1417,9 @@ int main(int argc, char **argv) {
|
||||
if (probe) {
|
||||
char line[256];
|
||||
if (fgets(line, sizeof(line), probe)) {
|
||||
if (sscanf(line, "%d/%d", &original_fps_num, &original_fps_den) != 2) {
|
||||
original_fps_num = 24;
|
||||
original_fps_den = 1;
|
||||
if (sscanf(line, "%d/%d", &enc.original_fps_num, &enc.original_fps_den) != 2) {
|
||||
enc.original_fps_num = 24;
|
||||
enc.original_fps_den = 1;
|
||||
}
|
||||
}
|
||||
pclose(probe);
|
||||
@@ -1411,8 +1427,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
// If user didn't specify target fps, use probed fps
|
||||
if (enc.target_fps_num == 0) {
|
||||
enc.fps_num = original_fps_num;
|
||||
enc.fps_den = original_fps_den;
|
||||
enc.fps_num = enc.original_fps_num;
|
||||
enc.fps_den = enc.original_fps_den;
|
||||
}
|
||||
|
||||
printf("\nTAV-DT Encoder (Revised Spec 2025-12-11)\n");
|
||||
@@ -1420,15 +1436,23 @@ int main(int argc, char **argv) {
|
||||
enc.is_interlaced ? "interlaced" : "progressive");
|
||||
printf(" Resolution: %dx%d (internal: %dx%d)\n", enc.width, enc.height,
|
||||
enc.width, enc.is_interlaced ? enc.height / 2 : enc.height);
|
||||
printf(" Source framerate: %d/%d\n", enc.original_fps_num, enc.original_fps_den);
|
||||
|
||||
// Report fps conversion if enabled
|
||||
if (enc.target_fps_num > 0 &&
|
||||
(enc.target_fps_num != original_fps_num || enc.target_fps_den != original_fps_den)) {
|
||||
printf(" Framerate: %d/%d -> %d/%d (conversion)\n",
|
||||
original_fps_num, original_fps_den,
|
||||
enc.target_fps_num, enc.target_fps_den);
|
||||
} else {
|
||||
printf(" Framerate: %d/%d\n", enc.fps_num, enc.fps_den);
|
||||
if (enc.target_fps_num > 0) {
|
||||
long long target_rate = (long long)enc.target_fps_num * enc.original_fps_den;
|
||||
long long source_rate = (long long)enc.original_fps_num * enc.target_fps_den;
|
||||
|
||||
if (target_rate > source_rate) {
|
||||
printf(" Framerate conversion: %d/%d -> %d/%d (minterpolate)\n",
|
||||
enc.original_fps_num, enc.original_fps_den,
|
||||
enc.target_fps_num, enc.target_fps_den);
|
||||
} else if (target_rate < source_rate) {
|
||||
printf(" Framerate conversion: %d/%d -> %d/%d (fps)\n",
|
||||
enc.original_fps_num, enc.original_fps_den,
|
||||
enc.target_fps_num, enc.target_fps_den);
|
||||
}
|
||||
// If equal, no conversion message needed
|
||||
}
|
||||
printf(" Quality: %d\n", enc.quality_index);
|
||||
printf(" GOP size: %d\n", DT_GOP_SIZE);
|
||||
|
||||
Reference in New Issue
Block a user