# MP4

> Encode an MP4 file with H.264, H.265, or AV1 and configure its video settings.

MP4 outputs use H.264, H.265, or AV1 video with AAC audio when the Source has audio. Choose the codec your target players support, then set the dimensions and quality you need.

## Codec defaults

| Format ID | Default CRF | Default preset |
| --- | --- | --- |
| `mp4_h264` | 21 | `faster` |
| `mp4_h265` | 24 | `veryfast` |
| `mp4_av1` | 35 | `8` |

These CRF defaults apply when you omit both per-title optimization and target bitrate. MP4 outputs use `movflags: faststart` and `pixfmt: yuv420p` by default.

## Create an H.264 transcode

The example sets a height of 720 pixels and CRF 21. Width follows the Source aspect ratio.

Run these examples on your server after [setting up your SDK and Source](/docs/transcoding/quickstart#before-you-begin). Replace the token and Source ID.

These examples save the file in your Project's output storage. Set `storage.path` to the filename you want to use.

<ignore>
SDK publication check: drafted from api/openapi.json and existing SDK conventions. Add Transcodings models, create/retrieve/list/cancel/delete mappings, pagination and data unwrapping to the owning SDK generator configuration. Verify generated method names and Go union/format/storage types in TypeScript, Python, PHP and Go before publication.
</ignore>

<codegroup>
<codeblock lang="TypeScript">
```typescript
import Chunkify from '@chunkify/chunkify';

async function main() {
    const client = new Chunkify({
        projectAccessToken: 'My Project Access Token',
    });

    const transcoding = await client.transcodings.create({
        source_id: 'src_2G6MJiNz71bHQGNzGwKx5cJwPFS',
        format: {
            id: "mp4_h264",
            height: 720,
            crf: 21,
        },
        storage: {
            path: 'exports/video-720p.mp4',
        },
    });

    console.log(transcoding.id, transcoding.status);
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});
```
</codeblock>
<codeblock lang="Python">
```python
from chunkify import Chunkify

client = Chunkify(
    project_access_token="My Project Access Token",
)

transcoding = client.transcodings.create(
    source_id="src_2G6MJiNz71bHQGNzGwKx5cJwPFS",
    format={
        "id": "mp4_h264",
        "height": 720,
        "crf": 21,
    },
    storage={
        "path": "exports/video-720p.mp4",
    },
)

print(transcoding.id, transcoding.status)
```
</codeblock>
<codeblock lang="PHP">
```php
<?php

use Chunkify\Client;

require_once __DIR__ . '/vendor/autoload.php';

$client = new Client(
    projectAccessToken: 'My Project Access Token',
);

$transcoding = $client->transcodings->create(
    sourceID: 'src_2G6MJiNz71bHQGNzGwKx5cJwPFS',
    format: [
        'id' => 'mp4_h264',
        'height' => 720,
        'crf' => 21,
    ],
    storage: [
        'path' => 'exports/video-720p.mp4',
    ],
);

var_dump($transcoding->id, $transcoding->status);
```
</codeblock>
<codeblock lang="Go">
```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/chunkifydev/chunkify-go"
	"github.com/chunkifydev/chunkify-go/option"
)

func main() {
	client := chunkify.NewClient(
		option.WithProjectAccessToken("My Project Access Token"),
	)

	transcoding, err := client.Transcodings.New(
		context.Background(),
		chunkify.TranscodingNewParams{
			SourceID: "src_2G6MJiNz71bHQGNzGwKx5cJwPFS",
			Format: chunkify.TranscodingNewParamsFormatUnion{
				OfMP4H264: &chunkify.TranscodingMP4H264Param{
					Height: chunkify.Int(720),
					Crf:    chunkify.Int(21),
				},
			},
			Storage: chunkify.TranscodingNewParamsStorage{
				Path: chunkify.String("exports/video-720p.mp4"),
			},
		},
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(transcoding.ID, transcoding.Status)
}
```
</codeblock>
</codegroup>

## Rate control and compatibility

Set `per_title: true` for automatic, content-based bitrate selection instead of specifying a CRF or target bitrate. See [Per-title optimization](/docs/transcoding/per-title).

For H.264 and H.265, `maxrate` and `bufsize` must be supplied together. AV1 permits a maximum rate with CRF encoding, but does not accept `minrate` or a maximum rate combined with `video_bitrate`.

A chosen `profilev` must support the requested pixel format. An explicit codec `level` must fit the dimensions, frame rate, bitrate, and buffer settings. Use the request schemas below to check valid combinations.

## Encoding parameters

<tabs>
    <tab title="H.264">
        <openapi-schema schema="#/components/schemas/TranscodingMp4H264"></openapi-schema>
    </tab>
    <tab title="H.265">
        <openapi-schema schema="#/components/schemas/TranscodingMp4H265"></openapi-schema>
    </tab>
    <tab title="AV1">
        <openapi-schema schema="#/components/schemas/TranscodingMp4Av1"></openapi-schema>
    </tab>
</tabs>
