| 12286 | } |
| 12287 | |
| 12288 | sam3_image sam3_decode_video_frame(const std::string& video_path, int frame_index) { |
| 12289 | sam3_image img; |
| 12290 | |
| 12291 | // Use ffmpeg to extract a single frame as raw RGB (frame-accurate) |
| 12292 | char cmd[1024]; |
| 12293 | snprintf(cmd, sizeof(cmd), |
| 12294 | "ffmpeg -nostdin -loglevel error -i \"%s\" " |
| 12295 | "-vf \"select=eq(n\\,%d)\" -vsync vfr -frames:v 1 " |
| 12296 | "-f rawvideo -pix_fmt rgb24 pipe:1 2>%s", |
| 12297 | video_path.c_str(), frame_index, SAM3_NULL_DEV); |
| 12298 | |
| 12299 | // First, get dimensions |
| 12300 | char info_cmd[1024]; |
| 12301 | snprintf(info_cmd, sizeof(info_cmd), |
| 12302 | "ffprobe -v error -select_streams v:0 " |
| 12303 | "-show_entries stream=width,height -of csv=p=0 \"%s\" 2>%s", |
| 12304 | video_path.c_str(), SAM3_NULL_DEV); |
| 12305 | FILE* fp = popen(info_cmd, SAM3_POPEN_READ); |
| 12306 | if (!fp) return img; |
| 12307 | int w = 0, h = 0; |
| 12308 | if (fscanf(fp, "%d,%d", &w, &h) != 2) { |
| 12309 | pclose(fp); |
| 12310 | return img; |
| 12311 | } |
| 12312 | pclose(fp); |
| 12313 | |
| 12314 | img.width = w; |
| 12315 | img.height = h; |
| 12316 | img.channels = 3; |
| 12317 | img.data.resize(w * h * 3); |
| 12318 | |
| 12319 | fp = popen(cmd, SAM3_POPEN_READ); |
| 12320 | if (!fp) { |
| 12321 | img.data.clear(); |
| 12322 | return img; |
| 12323 | } |
| 12324 | size_t nread = fread(img.data.data(), 1, img.data.size(), fp); |
| 12325 | pclose(fp); |
| 12326 | if (nread != img.data.size()) { |
| 12327 | img.data.clear(); |
| 12328 | } |
| 12329 | |
| 12330 | return img; |
| 12331 | } |
| 12332 | |
| 12333 | sam3_video_info sam3_get_video_info(const std::string& video_path) { |
| 12334 | sam3_video_info info; |
no outgoing calls