# 如何录制带音频且有时长限制的视频

> 录制视频（带或不带音频），设置质量和时长限制，并获取 MP4 的路径。

Source: https://crossfly.dev/zh/docs/cookbook/device/gravar-video — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 如何录制带音频且有时长限制的视频

**目的。** 用设备的摄像头录制一段视频，可选择 **带音频**，限制
时长并选择质量，并获取 **`.mp4` 文件的路径**。

## 使用的 API
- `Camera.captureMode`（`Preview`）— 捕获模式：`PHOTO`、`MUTED_VIDEO`（无声视频）、`AUDIO_VIDEO`（视频 + 音频）。
- `Camera.videoTimeLimit`（`int`）— 以 **秒** 为单位的录制限制；`0` = 无限制。
- `Camera.videoQuality`（`AVQuality`）— `HIGH`、`MEDIUM`（`Camera` 的默认值）、`LOW`。每个值定义帧率、视频/音频码率以及立体声。
- `Camera.shot()` → `String` — 启动录制 UI 并返回 `.mp4` 的路径（或 `null`）。
- `PhotoPicker(Preview type)` — 当 `cameraType == PICKER` 时使用的 UI；它拥有公共字段 `videoTimeLimit` 和 `videoQuality`，`shot()` 会从 `Camera` 中预填这些字段。

> **注意。** 在 `PhotoPicker` 中，录制视频时，文件会保存到 `/sdcard/<timestamp>.mp4`。
> `videoTimeLimit` 会让 picker 的时间标签 **倒计时显示**。在 `AUDIO_VIDEO` 模式下
> 录制会包含音频（`GdxRecorder.startVideoWithAudio`），在 `MUTED_VIDEO` 模式下则不包含。
> 在 iOS 的视频模式下，`shot()` 会使用系统原生摄像头，并传入 `videoTimeLimit`/`videoQuality`。

## 完整示例（复制、粘贴并运行）

```java
package com.exemplo;

import dev.crossfly.ui.*;                   // Window, Component, Button, Label, UIConstants
import dev.crossfly.ui.layout.*;            // VerticalLayout
import dev.crossfly.device.*;               // Camera, Camera.AVQuality

/** 可执行的主界面。将 launcher 指向此类（classname）并运行：gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label resultado = new Label("");
      add(LAY_AUTO, resultado);

      Button acao = new Button("Gravar vídeo");
      acao.onAction(c ->
      {
         new Thread(() ->
         {
            Camera cam = new Camera();
            cam.cameraType     = UIConstants.CameraType.PICKER;     // CrossFly 的录制 UI
            cam.captureMode    = UIConstants.Preview.AUDIO_VIDEO;   // 带音频的视频（无声用 MUTED_VIDEO）
            cam.videoQuality   = Camera.AVQuality.HIGH;             // HIGH | MEDIUM | LOW
            cam.videoTimeLimit = 30;                                // 30s；0 = 无限制

            String mp4 = cam.shot();                                // .mp4 的路径，取消则为 null

            Component.onUI(() ->                                    // 返回在 paint thread 之外
               resultado.setText(mp4 != null ? "Vídeo: " + mp4 : "Cancelado"));
         }).start();
      });
      add(LAY_AUTO, acao);
   }
}
```

> 下面的片段只展示 **核心部分**。要运行它，请把它放进上面的 `MainWindow` 骨架里。

## 最小片段

```java
// 已在源码验证：Camera.java (captureMode/videoTimeLimit/videoQuality, shot()); PhotoPicker.java (startRecording, stopRecording)
import dev.crossfly.device.*;              // Camera, Camera.AVQuality
import dev.crossfly.ui.*;                  // Component, UIConstants.CameraType/Preview

new Thread(() -> {
   Camera cam = new Camera();
   cam.cameraType    = UIConstants.CameraType.PICKER;     // CrossFly 的录制 UI
   cam.captureMode   = UIConstants.Preview.AUDIO_VIDEO;   // 带音频的视频（无声用 MUTED_VIDEO）
   cam.videoQuality  = Camera.AVQuality.HIGH;             // HIGH | MEDIUM | LOW
   cam.videoTimeLimit = 30;                               // 30s；0 = 无限制

   String mp4 = cam.shot();                               // .mp4 的路径，取消则为 null

   Component.onUI(() -> {                                 // 返回在 paint thread 之外
      if (mp4 != null)
         usarVideo(mp4);
   });
}).start();
```

## 深入了解
- 摄像头指南：[设备摄像头](/docs/data-and-services/device-camera) · 组件：[PhotoPicker](/docs/ui/widgets/photopicker)
- 姊妹篇：[tirar-foto.md](/docs/cookbook/device/tirar-foto)
