Monorepo for Aesthetic.Computer aesthetic.computer
at main 731 lines 24 kB view raw
1// audio-decode.c — Streaming audio file decoder for DJ decks 2// Decodes MP3/WAV/FLAC/OGG/AAC via FFmpeg into a stereo float ring buffer. 3// Single-producer (decoder thread) / single-consumer (audio thread) lock-free design. 4 5#ifdef HAVE_AVCODEC 6 7#include "audio-decode.h" 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <math.h> 12 13#include <libavcodec/avcodec.h> 14#include <libavformat/avformat.h> 15#include <libavutil/opt.h> 16#include <libavutil/imgutils.h> 17#include <libavutil/channel_layout.h> 18#include <libswscale/swscale.h> 19#include <libswresample/swresample.h> 20 21extern void ac_log(const char *fmt, ...); 22 23// --- Internal helpers --- 24 25static void extract_metadata(ACDeckDecoder *d, AVFormatContext *fmt) { 26 const AVDictionaryEntry *tag = NULL; 27 tag = av_dict_get(fmt->metadata, "title", NULL, 0); 28 if (tag) snprintf(d->title, sizeof(d->title), "%s", tag->value); 29 tag = av_dict_get(fmt->metadata, "artist", NULL, 0); 30 if (tag) snprintf(d->artist, sizeof(d->artist), "%s", tag->value); 31} 32 33static int ring_available(ACDeckDecoder *d) { 34 return d->ring_write - d->ring_read; 35} 36 37static int ring_free(ACDeckDecoder *d) { 38 return d->ring_size - ring_available(d); 39} 40 41static void free_video_preview(ACDeckDecoder *d) { 42 if (!d) return; 43 if (d->video_frames) { 44 free(d->video_frames); 45 d->video_frames = NULL; 46 } 47 d->video_frame_count = 0; 48 d->video_width = 0; 49 d->video_height = 0; 50 d->video_fps = 0.0; 51 d->video_ready = 0; 52} 53 54// --- Decoder thread --- 55 56static void *decoder_thread_fn(void *arg) { 57 ACDeckDecoder *d = (ACDeckDecoder *)arg; 58 AVFormatContext *fmt_ctx = (AVFormatContext *)d->fmt_ctx; 59 AVCodecContext *codec_ctx = (AVCodecContext *)d->codec_ctx; 60 SwrContext *swr = (SwrContext *)d->swr; 61 62 AVPacket *pkt = av_packet_alloc(); 63 AVFrame *frame = av_frame_alloc(); 64 int max_out_samples = 8192; 65 float *resample_buf = NULL; 66 67 if (!pkt || !frame) { 68 d->error = 1; 69 snprintf(d->error_msg, sizeof(d->error_msg), "alloc failed"); 70 goto done; 71 } 72 73 // Temporary buffer for resampled output (enough for one decoded frame) 74 resample_buf = malloc(max_out_samples * 2 * sizeof(float)); // stereo 75 if (!resample_buf) { 76 d->error = 1; 77 snprintf(d->error_msg, sizeof(d->error_msg), "resample buf alloc failed"); 78 goto done; 79 } 80 81 while (d->thread_running) { 82 // Handle seek requests 83 if (d->seek_requested) { 84 int64_t ts = (int64_t)(d->seek_target * AV_TIME_BASE); 85 av_seek_frame(fmt_ctx, -1, ts, AVSEEK_FLAG_BACKWARD); 86 avcodec_flush_buffers(codec_ctx); 87 // Reset ring buffer 88 d->ring_write = 0; 89 d->ring_read = 0; 90 d->ring_frac = 0.0; 91 d->position = d->seek_target; 92 d->finished = 0; 93 d->seek_requested = 0; 94 } 95 96 // Pause: wait for signal 97 if (!d->decoding) { 98 pthread_mutex_lock(&d->mutex); 99 while (!d->decoding && d->thread_running && !d->seek_requested) { 100 pthread_cond_wait(&d->cond, &d->mutex); 101 } 102 pthread_mutex_unlock(&d->mutex); 103 continue; 104 } 105 106 // Ring buffer full: wait until consumer drains below 80% 107 if (ring_free(d) < d->ring_size / 5) { 108 pthread_mutex_lock(&d->mutex); 109 while (ring_free(d) < d->ring_size / 2 && d->thread_running && !d->seek_requested) { 110 pthread_cond_wait(&d->cond, &d->mutex); 111 } 112 pthread_mutex_unlock(&d->mutex); 113 continue; 114 } 115 116 // Read next packet 117 int ret = av_read_frame(fmt_ctx, pkt); 118 if (ret < 0) { 119 if (ret == AVERROR_EOF) { 120 d->finished = 1; 121 d->decoding = 0; 122 } else { 123 d->error = 1; 124 snprintf(d->error_msg, sizeof(d->error_msg), "read error: %d", ret); 125 } 126 continue; 127 } 128 129 if (pkt->stream_index != d->stream_idx) { 130 av_packet_unref(pkt); 131 continue; 132 } 133 134 ret = avcodec_send_packet(codec_ctx, pkt); 135 av_packet_unref(pkt); 136 if (ret < 0) continue; 137 138 while (ret >= 0) { 139 ret = avcodec_receive_frame(codec_ctx, frame); 140 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; 141 if (ret < 0) { d->error = 1; break; } 142 143 // Resample: source rate -> output rate (always 1x, speed applied at playback) 144 int out_samples = av_rescale_rnd( 145 swr_get_delay(swr, d->src_sample_rate) + frame->nb_samples, 146 d->out_rate, 147 d->src_sample_rate, 148 AV_ROUND_UP 149 ); 150 151 if (out_samples > max_out_samples) { 152 max_out_samples = out_samples + 1024; 153 float *newbuf = realloc(resample_buf, max_out_samples * 2 * sizeof(float)); 154 if (!newbuf) { d->error = 1; break; } 155 resample_buf = newbuf; 156 } 157 158 uint8_t *out_planes[1] = { (uint8_t *)resample_buf }; 159 int converted = swr_convert(swr, 160 out_planes, out_samples, 161 (const uint8_t **)frame->data, frame->nb_samples); 162 163 if (converted <= 0) continue; 164 165 // Write to ring buffer 166 int free_frames = ring_free(d); 167 int to_write = converted < free_frames ? converted : free_frames; 168 169 for (int i = 0; i < to_write; i++) { 170 int wi = (d->ring_write % d->ring_size) * 2; 171 d->ring[wi] = resample_buf[i * 2]; 172 d->ring[wi + 1] = resample_buf[i * 2 + 1]; 173 d->ring_write++; 174 } 175 176 // Update position based on decoded frame PTS 177 if (frame->pts != AV_NOPTS_VALUE) { 178 AVStream *st = fmt_ctx->streams[d->stream_idx]; 179 d->position = frame->pts * av_q2d(st->time_base); 180 } 181 182 av_frame_unref(frame); 183 } 184 } 185 186done: 187 free(resample_buf); 188 av_packet_free(&pkt); 189 av_frame_free(&frame); 190 return NULL; 191} 192 193// --- Public API --- 194 195ACDeckDecoder *deck_decoder_create(unsigned int output_rate) { 196 ACDeckDecoder *d = calloc(1, sizeof(ACDeckDecoder)); 197 if (!d) return NULL; 198 199 d->out_rate = output_rate; 200 d->speed = 1.0; 201 d->ring_frac = 0.0; 202 d->ring_size = output_rate * DECK_RING_SECONDS; 203 d->ring = calloc(d->ring_size * 2, sizeof(float)); // stereo interleaved 204 if (!d->ring) { 205 free(d); 206 return NULL; 207 } 208 209 pthread_mutex_init(&d->mutex, NULL); 210 pthread_cond_init(&d->cond, NULL); 211 212 return d; 213} 214 215int deck_decoder_load(ACDeckDecoder *d, const char *path) { 216 if (!d) return -1; 217 218 // Unload any previous file 219 deck_decoder_unload(d); 220 221 // Reset state 222 d->loaded = 0; 223 d->finished = 0; 224 d->error = 0; 225 d->error_msg[0] = '\0'; 226 d->title[0] = '\0'; 227 d->artist[0] = '\0'; 228 d->position = 0.0; 229 d->duration = 0.0; 230 d->ring_write = 0; 231 d->ring_read = 0; 232 d->seek_requested = 0; 233 d->speed = 1.0; 234 snprintf(d->path, sizeof(d->path), "%s", path); 235 free_video_preview(d); 236 237 // Open file 238 AVFormatContext *fmt_ctx = NULL; 239 int ret = avformat_open_input(&fmt_ctx, path, NULL, NULL); 240 if (ret < 0) { 241 snprintf(d->error_msg, sizeof(d->error_msg), "cannot open: %s", path); 242 d->error = 1; 243 return -1; 244 } 245 246 ret = avformat_find_stream_info(fmt_ctx, NULL); 247 if (ret < 0) { 248 snprintf(d->error_msg, sizeof(d->error_msg), "no stream info"); 249 avformat_close_input(&fmt_ctx); 250 d->error = 1; 251 return -1; 252 } 253 254 // Find best audio stream 255 int stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); 256 if (stream_idx < 0) { 257 snprintf(d->error_msg, sizeof(d->error_msg), "no audio stream"); 258 avformat_close_input(&fmt_ctx); 259 d->error = 1; 260 return -1; 261 } 262 263 AVStream *st = fmt_ctx->streams[stream_idx]; 264 const AVCodec *codec = avcodec_find_decoder(st->codecpar->codec_id); 265 if (!codec) { 266 snprintf(d->error_msg, sizeof(d->error_msg), "unsupported codec"); 267 avformat_close_input(&fmt_ctx); 268 d->error = 1; 269 return -1; 270 } 271 272 AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); 273 avcodec_parameters_to_context(codec_ctx, st->codecpar); 274 ret = avcodec_open2(codec_ctx, codec, NULL); 275 if (ret < 0) { 276 snprintf(d->error_msg, sizeof(d->error_msg), "codec open failed"); 277 avcodec_free_context(&codec_ctx); 278 avformat_close_input(&fmt_ctx); 279 d->error = 1; 280 return -1; 281 } 282 283 // Setup resampler: source format -> stereo float at output rate 284 SwrContext *swr = NULL; 285 AVChannelLayout out_layout = AV_CHANNEL_LAYOUT_STEREO; 286 ret = swr_alloc_set_opts2(&swr, 287 &out_layout, AV_SAMPLE_FMT_FLT, d->out_rate, 288 &codec_ctx->ch_layout, codec_ctx->sample_fmt, codec_ctx->sample_rate, 289 0, NULL); 290 if (ret < 0 || !swr) { 291 snprintf(d->error_msg, sizeof(d->error_msg), "resampler alloc failed"); 292 avcodec_free_context(&codec_ctx); 293 avformat_close_input(&fmt_ctx); 294 d->error = 1; 295 return -1; 296 } 297 ret = swr_init(swr); 298 if (ret < 0) { 299 snprintf(d->error_msg, sizeof(d->error_msg), "resampler init failed"); 300 swr_free(&swr); 301 avcodec_free_context(&codec_ctx); 302 avformat_close_input(&fmt_ctx); 303 d->error = 1; 304 return -1; 305 } 306 307 // Store FFmpeg state 308 d->fmt_ctx = fmt_ctx; 309 d->codec_ctx = codec_ctx; 310 d->swr = swr; 311 d->stream_idx = stream_idx; 312 d->src_sample_rate = codec_ctx->sample_rate; 313 d->src_channels = codec_ctx->ch_layout.nb_channels; 314 315 // Duration 316 if (fmt_ctx->duration > 0) 317 d->duration = (double)fmt_ctx->duration / AV_TIME_BASE; 318 else if (st->duration > 0) 319 d->duration = st->duration * av_q2d(st->time_base); 320 321 // Metadata 322 extract_metadata(d, fmt_ctx); 323 324 // Extract filename as fallback title 325 if (d->title[0] == '\0') { 326 const char *slash = strrchr(path, '/'); 327 const char *name = slash ? slash + 1 : path; 328 snprintf(d->title, sizeof(d->title), "%s", name); 329 // Strip extension 330 char *dot = strrchr(d->title, '.'); 331 if (dot) *dot = '\0'; 332 } 333 334 d->loaded = 1; 335 d->decoding = 0; // paused until play() is called 336 337 // Start decoder thread 338 d->thread_running = 1; 339 pthread_create(&d->thread, NULL, decoder_thread_fn, d); 340 341 ac_log("[deck] loaded: %s (%s - %s, %.1fs, %dHz %dch)\n", 342 path, d->artist, d->title, d->duration, 343 d->src_sample_rate, d->src_channels); 344 345 return 0; 346} 347 348void deck_decoder_play(ACDeckDecoder *d) { 349 if (!d || !d->loaded) return; 350 if (d->finished) { 351 // Restart from beginning 352 d->seek_requested = 1; 353 d->seek_target = 0.0; 354 } 355 d->decoding = 1; 356 pthread_mutex_lock(&d->mutex); 357 pthread_cond_signal(&d->cond); 358 pthread_mutex_unlock(&d->mutex); 359} 360 361void deck_decoder_pause(ACDeckDecoder *d) { 362 if (!d) return; 363 d->decoding = 0; 364} 365 366void deck_decoder_seek(ACDeckDecoder *d, double seconds) { 367 if (!d || !d->loaded) return; 368 if (seconds < 0) seconds = 0; 369 if (seconds > d->duration) seconds = d->duration; 370 d->seek_target = seconds; 371 d->seek_requested = 1; 372 // Wake thread if paused 373 pthread_mutex_lock(&d->mutex); 374 pthread_cond_signal(&d->cond); 375 pthread_mutex_unlock(&d->mutex); 376} 377 378void deck_decoder_set_speed(ACDeckDecoder *d, double speed) { 379 if (!d) return; 380 if (speed < -4.0) speed = -4.0; 381 if (speed > 4.0) speed = 4.0; 382 d->speed = speed; 383} 384 385void deck_decoder_unload(ACDeckDecoder *d) { 386 if (!d) return; 387 388 // Stop thread 389 if (d->thread_running) { 390 d->thread_running = 0; 391 d->decoding = 0; 392 pthread_mutex_lock(&d->mutex); 393 pthread_cond_signal(&d->cond); 394 pthread_mutex_unlock(&d->mutex); 395 pthread_join(d->thread, NULL); 396 } 397 398 // Free FFmpeg state 399 if (d->swr) { 400 SwrContext *swr = (SwrContext *)d->swr; 401 swr_free(&swr); 402 d->swr = NULL; 403 } 404 if (d->codec_ctx) { 405 AVCodecContext *ctx = (AVCodecContext *)d->codec_ctx; 406 avcodec_free_context(&ctx); 407 d->codec_ctx = NULL; 408 } 409 if (d->fmt_ctx) { 410 AVFormatContext *fmt = (AVFormatContext *)d->fmt_ctx; 411 avformat_close_input(&fmt); 412 d->fmt_ctx = NULL; 413 } 414 415 // Free peaks 416 if (d->peaks) { 417 free(d->peaks); 418 d->peaks = NULL; 419 d->peak_count = 0; 420 } 421 free_video_preview(d); 422 423 d->loaded = 0; 424 d->finished = 0; 425 d->decoding = 0; 426 d->ring_write = 0; 427 d->ring_read = 0; 428} 429 430// Generate decimated max-amplitude peaks for the loaded file. 431// Opens a SECOND independent FFmpeg context (so it doesn't disturb playback) 432// and decodes the entire file once, recording max abs value per chunk. 433int deck_decoder_generate_peaks(ACDeckDecoder *d, int target_count) { 434 if (!d || !d->loaded || !d->path[0]) return -1; 435 if (d->peaks) { free(d->peaks); d->peaks = NULL; d->peak_count = 0; } 436 if (target_count <= 0) target_count = 1024; 437 438 AVFormatContext *fmt = NULL; 439 if (avformat_open_input(&fmt, d->path, NULL, NULL) < 0) return -1; 440 if (avformat_find_stream_info(fmt, NULL) < 0) { 441 avformat_close_input(&fmt); 442 return -1; 443 } 444 int sidx = av_find_best_stream(fmt, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); 445 if (sidx < 0) { avformat_close_input(&fmt); return -1; } 446 AVStream *st = fmt->streams[sidx]; 447 const AVCodec *codec = avcodec_find_decoder(st->codecpar->codec_id); 448 if (!codec) { avformat_close_input(&fmt); return -1; } 449 AVCodecContext *cctx = avcodec_alloc_context3(codec); 450 avcodec_parameters_to_context(cctx, st->codecpar); 451 if (avcodec_open2(cctx, codec, NULL) < 0) { 452 avcodec_free_context(&cctx); 453 avformat_close_input(&fmt); 454 return -1; 455 } 456 457 // Estimate total samples for chunking 458 double duration = d->duration; 459 if (duration <= 0) duration = 60.0; // fallback 460 int sample_rate = cctx->sample_rate; 461 long total_samples = (long)(duration * sample_rate); 462 if (total_samples < target_count) total_samples = target_count; 463 long samples_per_chunk = total_samples / target_count; 464 if (samples_per_chunk < 1) samples_per_chunk = 1; 465 466 d->peaks = (float *)calloc(target_count, sizeof(float)); 467 if (!d->peaks) { 468 avcodec_free_context(&cctx); 469 avformat_close_input(&fmt); 470 return -1; 471 } 472 d->peak_count = target_count; 473 474 // Setup converter to mono float 475 SwrContext *swr = NULL; 476 AVChannelLayout out_layout = AV_CHANNEL_LAYOUT_MONO; 477 swr_alloc_set_opts2(&swr, &out_layout, AV_SAMPLE_FMT_FLT, sample_rate, 478 &cctx->ch_layout, cctx->sample_fmt, cctx->sample_rate, 479 0, NULL); 480 swr_init(swr); 481 482 AVPacket *pkt = av_packet_alloc(); 483 AVFrame *frame = av_frame_alloc(); 484 float chunk_max = 0.0f; 485 long sample_idx = 0; 486 int peak_idx = 0; 487 float *outbuf = (float *)malloc(sample_rate * sizeof(float)); 488 int outbuf_size = sample_rate; 489 490 while (av_read_frame(fmt, pkt) >= 0 && peak_idx < target_count) { 491 if (pkt->stream_index != sidx) { av_packet_unref(pkt); continue; } 492 if (avcodec_send_packet(cctx, pkt) < 0) { av_packet_unref(pkt); continue; } 493 while (avcodec_receive_frame(cctx, frame) >= 0) { 494 int max_out = frame->nb_samples + 256; 495 if (max_out > outbuf_size) { 496 outbuf = (float *)realloc(outbuf, max_out * sizeof(float)); 497 outbuf_size = max_out; 498 } 499 uint8_t *out_ptr[1] = { (uint8_t *)outbuf }; 500 int out_n = swr_convert(swr, out_ptr, max_out, 501 (const uint8_t **)frame->data, frame->nb_samples); 502 for (int i = 0; i < out_n; i++) { 503 float v = outbuf[i]; 504 if (v < 0) v = -v; 505 if (v > chunk_max) chunk_max = v; 506 sample_idx++; 507 if (sample_idx >= samples_per_chunk) { 508 if (peak_idx < target_count) { 509 d->peaks[peak_idx++] = chunk_max; 510 } 511 chunk_max = 0.0f; 512 sample_idx = 0; 513 } 514 } 515 } 516 av_packet_unref(pkt); 517 } 518 // Final chunk 519 if (peak_idx < target_count && chunk_max > 0) { 520 d->peaks[peak_idx++] = chunk_max; 521 } 522 // Fill remaining 523 while (peak_idx < target_count) d->peaks[peak_idx++] = 0; 524 525 free(outbuf); 526 av_frame_free(&frame); 527 av_packet_free(&pkt); 528 swr_free(&swr); 529 avcodec_free_context(&cctx); 530 avformat_close_input(&fmt); 531 532 return target_count; 533} 534 535int deck_decoder_generate_video_preview(ACDeckDecoder *d, int width, int height, int fps) { 536 if (!d || !d->loaded || !d->path[0]) return -1; 537 if (width <= 0) width = 96; 538 if (height <= 0) height = 54; 539 if (fps <= 0) fps = 12; 540 if (fps > 24) fps = 24; 541 542 // Reuse cached preview when the request matches the existing buffer. 543 if (d->video_ready && 544 d->video_frames && 545 d->video_width == width && 546 d->video_height == height && 547 fabs(d->video_fps - (double)fps) < 0.001) { 548 return d->video_frame_count; 549 } 550 551 free_video_preview(d); 552 553 AVFormatContext *fmt = NULL; 554 if (avformat_open_input(&fmt, d->path, NULL, NULL) < 0) return -1; 555 if (avformat_find_stream_info(fmt, NULL) < 0) { 556 avformat_close_input(&fmt); 557 return -1; 558 } 559 560 int sidx = av_find_best_stream(fmt, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); 561 if (sidx < 0) { 562 avformat_close_input(&fmt); 563 return -1; 564 } 565 566 AVStream *st = fmt->streams[sidx]; 567 const AVCodec *codec = avcodec_find_decoder(st->codecpar->codec_id); 568 if (!codec) { 569 avformat_close_input(&fmt); 570 return -1; 571 } 572 573 AVCodecContext *cctx = avcodec_alloc_context3(codec); 574 if (!cctx) { 575 avformat_close_input(&fmt); 576 return -1; 577 } 578 avcodec_parameters_to_context(cctx, st->codecpar); 579 if (avcodec_open2(cctx, codec, NULL) < 0) { 580 avcodec_free_context(&cctx); 581 avformat_close_input(&fmt); 582 return -1; 583 } 584 585 double duration = d->duration; 586 if (duration <= 0.0 && fmt->duration > 0) 587 duration = (double)fmt->duration / AV_TIME_BASE; 588 if (duration <= 0.0 && st->duration > 0) 589 duration = st->duration * av_q2d(st->time_base); 590 if (duration <= 0.0) 591 duration = 30.0; 592 593 int target_count = (int)ceil(duration * (double)fps) + 1; 594 if (target_count < 1) target_count = 1; 595 if (target_count > 900) target_count = 900; 596 597 size_t pixels_per_frame = (size_t)width * (size_t)height; 598 size_t total_pixels = pixels_per_frame * (size_t)target_count; 599 uint32_t *frames = (uint32_t *)calloc(total_pixels, sizeof(uint32_t)); 600 if (!frames) { 601 avcodec_free_context(&cctx); 602 avformat_close_input(&fmt); 603 return -1; 604 } 605 606 struct SwsContext *sws = sws_getContext( 607 cctx->width, cctx->height, cctx->pix_fmt, 608 width, height, AV_PIX_FMT_BGRA, 609 SWS_BILINEAR, NULL, NULL, NULL); 610 if (!sws) { 611 free(frames); 612 avcodec_free_context(&cctx); 613 avformat_close_input(&fmt); 614 return -1; 615 } 616 617 AVPacket *pkt = av_packet_alloc(); 618 AVFrame *frame = av_frame_alloc(); 619 if (!pkt || !frame) { 620 av_packet_free(&pkt); 621 av_frame_free(&frame); 622 sws_freeContext(sws); 623 free(frames); 624 avcodec_free_context(&cctx); 625 avformat_close_input(&fmt); 626 return -1; 627 } 628 629 uint8_t *last_frame = NULL; 630 int frame_idx = 0; 631 double next_time = 0.0; 632 633 while (av_read_frame(fmt, pkt) >= 0 && frame_idx < target_count) { 634 if (pkt->stream_index != sidx) { 635 av_packet_unref(pkt); 636 continue; 637 } 638 if (avcodec_send_packet(cctx, pkt) < 0) { 639 av_packet_unref(pkt); 640 continue; 641 } 642 av_packet_unref(pkt); 643 644 while (avcodec_receive_frame(cctx, frame) >= 0 && frame_idx < target_count) { 645 double frame_time = 0.0; 646 if (frame->best_effort_timestamp != AV_NOPTS_VALUE) 647 frame_time = frame->best_effort_timestamp * av_q2d(st->time_base); 648 else if (frame->pts != AV_NOPTS_VALUE) 649 frame_time = frame->pts * av_q2d(st->time_base); 650 651 uint8_t *dst_data[4] = {0}; 652 int dst_linesize[4] = {0}; 653 uint32_t *dst = frames + ((size_t)frame_idx * pixels_per_frame); 654 av_image_fill_arrays(dst_data, dst_linesize, (uint8_t *)dst, 655 AV_PIX_FMT_BGRA, width, height, 1); 656 657 // Fill every preview sample point that this decoded frame covers. 658 while (frame_idx < target_count && 659 (frame_time >= next_time || frame_idx == 0)) { 660 dst = frames + ((size_t)frame_idx * pixels_per_frame); 661 av_image_fill_arrays(dst_data, dst_linesize, (uint8_t *)dst, 662 AV_PIX_FMT_BGRA, width, height, 1); 663 sws_scale(sws, (const uint8_t * const *)frame->data, frame->linesize, 664 0, cctx->height, dst_data, dst_linesize); 665 last_frame = (uint8_t *)dst; 666 frame_idx++; 667 next_time = (double)frame_idx / (double)fps; 668 } 669 670 av_frame_unref(frame); 671 } 672 } 673 674 // Flush decoder for the tail of the file. 675 avcodec_send_packet(cctx, NULL); 676 while (avcodec_receive_frame(cctx, frame) >= 0 && frame_idx < target_count) { 677 uint8_t *dst_data[4] = {0}; 678 int dst_linesize[4] = {0}; 679 uint32_t *dst = frames + ((size_t)frame_idx * pixels_per_frame); 680 av_image_fill_arrays(dst_data, dst_linesize, (uint8_t *)dst, 681 AV_PIX_FMT_BGRA, width, height, 1); 682 sws_scale(sws, (const uint8_t * const *)frame->data, frame->linesize, 683 0, cctx->height, dst_data, dst_linesize); 684 last_frame = (uint8_t *)dst; 685 frame_idx++; 686 av_frame_unref(frame); 687 } 688 689 // Pad remaining preview slots with the final decoded frame so playback 690 // keeps showing a still image once audio reaches the tail. 691 if (last_frame) { 692 while (frame_idx < target_count) { 693 uint32_t *dst = frames + ((size_t)frame_idx * pixels_per_frame); 694 memcpy(dst, last_frame, pixels_per_frame * sizeof(uint32_t)); 695 frame_idx++; 696 } 697 } 698 699 av_packet_free(&pkt); 700 av_frame_free(&frame); 701 sws_freeContext(sws); 702 avcodec_free_context(&cctx); 703 avformat_close_input(&fmt); 704 705 if (frame_idx <= 0) { 706 free(frames); 707 return -1; 708 } 709 710 d->video_frames = frames; 711 d->video_frame_count = frame_idx; 712 d->video_width = width; 713 d->video_height = height; 714 d->video_fps = (double)fps; 715 d->video_ready = 1; 716 717 ac_log("[deck] video preview ready: %s (%d frames @ %dx%d %.1ffps)\n", 718 d->path, d->video_frame_count, d->video_width, d->video_height, d->video_fps); 719 return d->video_frame_count; 720} 721 722void deck_decoder_destroy(ACDeckDecoder *d) { 723 if (!d) return; 724 deck_decoder_unload(d); 725 free(d->ring); 726 pthread_mutex_destroy(&d->mutex); 727 pthread_cond_destroy(&d->cond); 728 free(d); 729} 730 731#endif // HAVE_AVCODEC