# Merge and transcode recorded files (/en/realtime-media/cloud-recording/build/process-recorded-files/merge-files)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

After completing a cloud recording session, you can use Agora's transcoding script to merge and convert raw recorded files such as `.m3u8`, `.ts`, and `.webm` formats into standard `.m4a` or `.mp4` media files. This guide describes how to use the transcoding script across different recording modes and provides typical use cases and examples to help you generate your target audio and video files.

## Prerequisites [#prerequisites]

Agora recommends hosting your transcoding engine on a server that matches the following specifications:

* **Architecture:** Linux AMD64 (`x86_64`)
* **Operating System:** Ubuntu 24.04 LTS or later
* **Runtime:** Python 3.12 or later

### File preparation [#file-preparation]

* **Ensure complete file delivery:** Verify that all initial recorded files have been generated by the Agora Cloud Recording RESTful API. For details on asset structural composition and schema conventions, see [Composition of Recording Files](/en/realtime-media/cloud-recording/build/process-recorded-files/manage-files). Any missing index or segment files will cause the transcoding pipeline to fail.

* **Verify storage permissions:** Ensure that the local or remote storage directory path hosting the generated recording assets is accessible and readable by your transcoding server process.

### Get the script [#get-the-script]

Download the Agora audio and video format conversion script package and extract its contents. Navigate to the directory containing the extracted script before running it.

Agora recommends using the bundled copies of `ffmpeg`, `ffprobe`, and `transcoder` included within the package to avoid potential software compatibility issues.

The package contains the following files:

| File            | Purpose                                                                                                                                                                                                                                              |
| :-------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `convert_v2.py` | The primary entry point script for transcoding. It scans your recorded files based on parameters such as `--dir` and invokes the local instances of ffmpeg, ffprobe, and transcoder to execute file merging, container repackaging, and transcoding. |
| `ffmpeg`        | An audio and video processing executable. It handles stream copying, container multiplexing, and final encoding outputs.                                                                                                                             |
| `ffprobe`       | A media information probing executable. It reads stream attributes, including resolution dimensions, frame rates, and audio channel layouts, and passes them to the script and ffmpeg.                                                               |
| `transcoder`    | A core transcoding executable. It is invoked directly by the script to handle file decoding and stream mixing, passing its output to ffmpeg for final file packaging.                                                                                |

<CalloutContainer type="warning">
  <CalloutDescription>
    The transcoding script requires a compatible runtime environment. If you run the script on Windows or any non-Linux AMD64 operating system architecture, it will return an error and terminate.
  </CalloutDescription>
</CalloutContainer>

## Convert recorded files with the script [#convert-recorded-files-with-the-script]

After navigating to the script directory, the script scans and transcodes files in the target directory using individual recording mode by default. When converting default individual recordings, you only need to specify the path to the directory containing your recorded assets.

There is only one required parameter:

* **`--dir {directory_path}`:** Specifies the directory containing the `.m3u8`, `.ts`, or `.webm` files generated during your recording session. The script scans this path, automatically identifies assets based on individual recording logic, and transcodes them sequentially. The script automatically determines the output format based on the source tracks, generating an `.mp4` file for audio-video tracks, an `.m4a` file for audio-only tracks, and an `.mp4` file for video-only tracks.

<CalloutContainer type="info">
  <CalloutDescription>
    If you are converting composite recordings or web page recordings, you must explicitly pass the `--recording_mode mix` or `--recording_mode web` parameters.
  </CalloutDescription>
</CalloutContainer>

### Minimal workflow example [#minimal-workflow-example]

The following example runs a basic transcoding task using the default configuration and the single required parameter:

```bash
cd /path/to/extracted-script-directory
python3 convert_v2.py --dir /path/to/recordings
```

This command transcodes all compatible recording assets located inside the directory specified by `--dir` and generates the output files within that same source folder.

If your workflow requires processing a specific user ID (`uid`), filtering outputs to audio or video only, or forcing a targeted resolution, you can append optional arguments such as `--uid`, `--avtype`, or `--recording_mode`. For a detailed breakdown of all available flags and their permitted configurations, see [Script Parameter Descriptions](#script-parameter-descriptions).

### Individual recording [#individual-recording]

In individual recording mode, the audio and video streams for each user ID in a session are recorded separately, generating distinct `.m3u8`, `.ts`, or `.webm` index and segment files. You can use the Agora format conversion script to merge the separate audio and video components for each user ID into unified media assets.

<Tabs defaultValue="all-users">
  <TabsList>
    <TabsTrigger value="all-users">
      Transcode entire session
    </TabsTrigger>

    <TabsTrigger value="specific-user">
      Transcode specific users
    </TabsTrigger>

    <TabsTrigger value="audio-video-only">
      Output audio or video only
    </TabsTrigger>

    <TabsTrigger value="abnormal-merge">
      Merge abnormal recordings
    </TabsTrigger>
  </TabsList>

  <TabsContent value="all-users">
    Use this approach when you need to convert the recorded files for all users inside the target directory into standard `.m4a` or `.mp4` formats. The script automatically determines the output layout, generating an `.mp4` file for users with both audio and video tracks, and an `.m4a` file for users with audio-only tracks.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings
    ```
  </TabsContent>

  <TabsContent value="specific-user">
    Use this approach when you only need to transcode the audio and video tracks of a single user. Note that the script processes only one user ID per execution loop. To transcode files for multiple specific users, run the command multiple times and pass a different target user ID to the `--uid` flag during each run.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings --uid 123456
    ```
  </TabsContent>

  <TabsContent value="audio-video-only">
    Use this approach when your workflow requires standalone audio files (`.m4a`) or standalone video files (`.mp4`) without merging the tracks into a combined file. Typical use cases include generating raw meeting transcripts or creating audio-only archives.

    ```bash
    # Audio only
    python3 convert_v2.py --dir /path/to/recordings --avtype audio_only

    # Video only
    python3 convert_v2.py --dir /path/to/recordings --avtype video_only
    ```
  </TabsContent>

  <TabsContent value="abnormal-merge">
    Use this approach to handle failover scenarios. If a recording server loses its network connection or a system process terminates unexpectedly, high-availability mechanisms trigger. When this happens, your storage directory will contain a mix of original `.m3u8` or `.ts` files alongside recovered files that carry a `bak<n>` prefix string.

    Running this command automatically groups, matches, and flattens the original assets and recovery files into a unified `.mp4` asset by validating matching user IDs, session IDs, and channel names.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings
    ```
  </TabsContent>
</Tabs>

### Composite recording [#composite-recording]

In composite recording mode, the recorded results are delivered as a single `.m3u8` index file and multiple `.ts` segment files. These assets contain the combined audio and video data for the entire composite recording session.

You can use the Agora format conversion script to merge these assets into standard media files. When transcoding composite recordings, you must explicitly set the `--recording_mode` parameter to `mix`.

<Tabs defaultValue="mix-mp4">
  <TabsList>
    <TabsTrigger value="mix-mp4">
      Convert entire session to MP4
    </TabsTrigger>

    <TabsTrigger value="mix-audio-video">
      Export audio or video only
    </TabsTrigger>

    <TabsTrigger value="mix-resolution">
      Specify output video resolution
    </TabsTrigger>

    <TabsTrigger value="mix-abnormal">
      Merge abnormal recordings
    </TabsTrigger>
  </TabsList>

  <TabsContent value="mix-mp4">
    Use this approach to convert an entire composite recording session into a standard, playable media asset in a single execution loop. The script automatically determines the output layout based on the source tracks, generating an `.mp4` file for audio-video tracks and an `.m4a` file for audio-only tracks.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings --recording_mode mix
    ```
  </TabsContent>

  <TabsContent value="mix-audio-video">
    Use this approach when your workflow requires standalone audio files (`.m4a`) or standalone video files (`.mp4`) without merging the tracks into a combined file. Typical use cases include generating raw meeting transcripts or creating audio-only archives.

    ```bash
    # Audio only
    python3 convert_v2.py --dir /path/to/recordings --recording_mode mix --avtype audio_only

    # Video only
    python3 convert_v2.py --dir /path/to/recordings --recording_mode mix --avtype video_only
    ```
  </TabsContent>

  <TabsContent value="mix-resolution">
    Use this approach when your workflow requires a unified, fixed video resolution profile (such as forcing the output to `1280` by `720` pixels) to satisfy specific downstream distribution, streaming playback, or media archiving compliance standards.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings --recording_mode mix --width 1280 --height 720
    ```
  </TabsContent>

  <TabsContent value="mix-abnormal">
    Use this approach to handle failover scenarios. If a recording server loses its network connection or a system process terminates unexpectedly, high-availability mechanisms trigger. When this happens, your storage directory will contain a mix of original `.m3u8` or `.ts` files alongside recovered files that carry a `bak<n>` prefix string.

    Running this command automatically groups, matches, and flattens the original assets and recovery files into a unified file by validating matching session IDs and channel names.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings --recording_mode mix
    ```
  </TabsContent>
</Tabs>

### Web page recording [#web-page-recording]

In web page recording mode, the recorded web content and audio, including the full page view, whiteboards, and courseware, are captured as a single `.m3u8` index file and multiple `.ts` segment files. These assets contain the combined audio and video data for the entire web page recording session.

You can use the Agora format conversion script to merge these assets into standard media files. When transcoding web page recordings, you must explicitly set the `--recording_mode` parameter to `web`.

<Tabs defaultValue="web-mp4">
  <TabsList>
    <TabsTrigger value="web-mp4">
      Convert entire session to MP4
    </TabsTrigger>

    <TabsTrigger value="web-audio-video">
      Export audio or video only
    </TabsTrigger>

    <TabsTrigger value="web-resolution">
      Specify output video resolution
    </TabsTrigger>

    <TabsTrigger value="web-abnormal">
      Merge abnormal recordings
    </TabsTrigger>
  </TabsList>

  <TabsContent value="web-mp4">
    Use this approach to convert an entire web page recording session into a standard, playable media asset in a single execution loop. The script automatically determines the output layout based on the source tracks, generating an `.mp4` file for audio-video tracks and an `.m4a` file for audio-only tracks.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings --recording_mode web
    ```
  </TabsContent>

  <TabsContent value="web-audio-video">
    Use this approach when your workflow requires standalone audio files (`.m4a`) or standalone video files (`.mp4`) without merging the tracks into a combined file. Typical use cases include generating raw meeting transcripts or creating audio-only archives.

    ```bash
    # Audio only
    python3 convert_v2.py --dir /path/to/recordings --recording_mode web --avtype audio_only

    # Video only
    python3 convert_v2.py --dir /path/to/recordings --recording_mode web --avtype video_only
    ```
  </TabsContent>

  <TabsContent value="web-resolution">
    Use this approach when your workflow requires a unified, fixed video resolution profile (such as forcing the output to `1280` by `720` pixels) to satisfy specific downstream distribution, streaming playback, or media archiving compliance standards.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings --recording_mode web --width 1280 --height 720
    ```
  </TabsContent>

  <TabsContent value="web-abnormal">
    Use this approach to handle failover scenarios. If a recording server loses its network connection or a system process terminates unexpectedly, high-availability mechanisms trigger. When this happens, your storage directory will contain a mix of original `.m3u8` or `.ts` files alongside recovered files that carry a `bak<n>` prefix string.

    Running this command automatically groups, matches, and flattens the original assets and recovery files into a unified file by validating matching session IDs and channel names.

    ```bash
    python3 convert_v2.py --dir /path/to/recordings --recording_mode web
    ```
  </TabsContent>
</Tabs>

## Reference [#reference]

### Script parameter descriptions [#script-parameter-descriptions]

The following table provides a detailed breakdown of the configurations and arguments available within the transcoding script.

| Parameter                                              | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Required |
| :----------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------- |
| `--dir {directory_path}`                               | Specifies the path to the directory containing your recorded assets (absolute paths are highly recommended). If the specified directory contains files belonging to multiple recording sessions, the script processes and transcodes them sequentially based on distinct task IDs.                                                                                                                                                                                                                                                                                                                            | **Yes**  |
| `--recording_mode {individual, mix, web}`              | Specifies the operational recording architecture profile. Valid options are:<br />`individual`: (Default) Individual stream recording mode.<br />`mix`: Composite stream recording mode.<br />`web`: Web page recording mode.                                                                                                                                                                                                                                                                                                                                                                                 | No       |
| `--uid {uid}`                                          | Filters the task loop to transcode the recording assets of a single, specified user ID. This flag supports only one user ID per loop. If this argument is omitted, the script automatically processes all available user IDs found inside the directory path. This parameter is valid only when operating under `individual` recording mode.                                                                                                                                                                                                                                                                  | No       |
| `--avtype {auto, audio_only, video_only, audio_video}` | Specifies the target track type layout for the output files. Valid options are:<br />`auto`: (Default) The script automatically determines the format based on the source tracks. Tracks containing both audio and video generate an `.mp4` file appended with an `_av` suffix marker. Audio-only tracks output as `.m4a` and video-only tracks output as `.mp4`.<br />`audio_only`: Extracts and outputs standalone audio files (`.m4a`).<br />`video_only`: Extracts and outputs standalone video files (`.mp4`).<br />`audio_video`: Forces the output to generate merged audio and video assets (`.mp4`). | No       |
| `--width {pixels}`                                     | Sets the target horizontal width resolution in pixels. If this flag is omitted, the script uses the native source track width. When configured alongside the `--height` flag, the final layout resolution must stay within the range of `120` by `120` pixels to `1920` by `1080` pixels.                                                                                                                                                                                                                                                                                                                     | No       |
| `--height {pixels}`                                    | Sets the target vertical height resolution in pixels. If this flag is omitted, the script uses the native source track height.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | No       |
| `--video_bitrate {kbps}`                               | Sets the output video encoding stream bandwidth in kbps. If this flag is omitted, the script preserves the native bit rate of the source files. The permitted adjustment profile extends from a value of `50` to `6300` kbps.                                                                                                                                                                                                                                                                                                                                                                                 | No       |
| `--video_framerate {fps}`                              | Sets the output video cadence layout in frames per second. If this flag is omitted, the script preserves the native frame rate of the source files. The permitted adjustment profile extends from a value of `5` to `60` fps.                                                                                                                                                                                                                                                                                                                                                                                 | No       |
| `--fill_strategy {black_frame, duplicate_prev}`        | Specifies the asset frame insertion recovery rule applied if data tracks drop temporarily. Valid options are:<br />`duplicate_prev`: (Default) Duplicates the last successfully decoded video frame to bridge any track gaps.<br />`black_frame`: Inserts solid black frames to fill any tracking voids.                                                                                                                                                                                                                                                                                                      | No       |

### Output filename descriptions [#output-filename-descriptions]

The naming convention of the generated files depends on the recording mode selected during the transcoding pipeline:

#### Individual recording mode [#individual-recording-mode]

Output files generated in individual mode use the target user ID (`{uid}`) as the filename prefix:

* **`{uid}_0_merge.mp4`:** Contains the video track only.
* **`{uid}_0_merge.m4a`:** Contains the audio track only.
* **`{uid}_0_merge_av.mp4`:** Contains the combined, synchronized audio and video tracks.

#### Composite and web page recording modes [#composite-and-web-page-recording-modes]

Output files generated in composite or web page recording modes use the session ID (`{sid}`), which represents the unique recording ID, as the filename prefix:

* **`{sid}_0_merge.mp4`:** Contains the video track only.
* **`{sid}_0_merge.m4a`:** Contains the audio track only.
* **`{sid}_0_merge_av.mp4`:** Contains the combined, synchronized audio and video tracks.
