MP4文件抽帧保存到本地

可以使用opencv-python库来处理MP4视频并抽取帧。以下是一个从MP4视频中抽取10帧并保存到本地的Python程序:

import cv2
import os
import math

def extract_frames(video_path, output_dir, num_frames=10):
“”"
从MP4视频中抽取指定数量的帧并保存

参数:
    video_path: MP4视频文件路径
    output_dir: 帧图片保存目录
    num_frames: 要抽取的帧数,默认10
"""
# 创建输出目录(如果不存在)
os.makedirs(output_dir, exist_ok=True)

# 打开视频文件
cap = cv2.VideoCapture(video_path)

# 检查视频是否成功打开
if not cap.isOpened():
    print(f"错误:无法打开视频文件 {video_path}")
    return

# 获取视频总帧数
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print(f"视频总帧数: {total_frames}")

# 计算需要抽取的帧的位置(均匀分布)
if total_frames < num_frames:
    print(f"警告:视频帧数({total_frames})少于需要抽取的帧数({num_frames}),将抽取所有帧")
    num_frames = total_frames

# 计算帧间隔
interval = math.floor(total_frames / num_frames)

extracted_count = 0
frame_idx = 0

# 循环读取视频帧
while extracted_count < num_frames:
    # 移动到指定帧
    cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)

    # 读取帧
    ret, frame = ca
明白了!你想在 `ExtractInternel()` 函数中取出第一,并**将它保存本地**,而不是跳过或者丢弃。这在调试、截图、关键提取等场景中非常常见。 你可以通过添加一个标志位来判断是否是第一次提取,如果是,则保存第一本地。以下是一个示例实现: --- ### ✅ 修改后的代码片段(增加“保存第一”逻辑): ```cpp std::vector<std::shared_ptr<AVSharedMemory>> AVMetaFrameExtractor::ExtractInternel() { std::vector<std::shared_ptr<AVSharedMemory>> outFrames; std::unique_lock<std::mutex> lock(mutex_); static constexpr int32_t timeout = 3; cond_.wait_for(lock, std::chrono::seconds(timeout), [this]() { return !originalFrames_.empty() || !startExtracting_; }); CHECK_AND_RETURN_RET_LOG(startExtracting_, outFrames, "cancelled, exit frame extract"); CHECK_AND_RETURN_RET_LOG(!originalFrames_.empty(), outFrames, "no more frames"); auto item = originalFrames_.front(); originalFrames_.pop(); auto frameConverter = std::move(frameConverter_); lock.unlock(); auto outFrame = frameConverter->Convert(*item.second, *item.first); if (outFrame == nullptr) { gst_buffer_unref(item.first); gst_caps_unref(item.second); MEDIA_LOGE("convert frame failed"); return outFrames; } // 新增:保存第一本地 if (isFirstFrame_) { // 假设 isFirstFrame_ 是类成员变量,初始为 true SaveFrameToLocal(*item.first); // 自定义函数,用于保存数据 isFirstFrame_ = false; // 设置标志为 false,后续不再保存 MEDIA_LOGD("first frame saved"); } gst_buffer_unref(item.first); gst_caps_unref(item.second); outFrames.push_back(outFrame); MEDIA_LOGD("extract frame success, frame number: %{public}zu", outFrames.size()); return outFrames; } ``` --- ### 🔧 需要你自己实现的函数: ```cpp void AVMetaFrameExtractor::SaveFrameToLocal(GstBuffer&amp; buffer) { // 示例:将 GstBuffer 写入文件 FILE* fp = fopen("first_frame.raw", "wb"); if (!fp) { MEDIA_LOGE("failed to open file for saving first frame"); return; } GstMapInfo map; if (gst_buffer_map(&amp;buffer, &amp;map, GST_MAP_READ)) { fwrite(map.data, 1, map.size, fp); gst_buffer_unmap(&amp;buffer, &amp;map); } fclose(fp); MEDIA_LOGD("first frame saved to first_frame.raw"); } ``` --- ### 📌 注意事项: - **`isFirstFrame_` 是类成员变量**,初始值为 `true`。 - 你可以在保存完成后将其置为 `false`,确保只保存一次。 - 如果你需要保存成图片格式(如 JPEG/PNG),还需要使用图像编码库(如 OpenCV 或 GStreamer 插件)进行转换后再保存。 - 若数据较大或频繁调用,建议异步保存以避免阻塞主线程。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值