> This page is for Camera to Cloud.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# 방법: 업로드(기본)

## 소개





이제 저희의 통합 여정에서 흥미로운 이정표에 도달했습니다. 바로 에셋을 Frame.io에 업로드하는 것입니다. 이 가이드는 기본적인 업로드 프로세스를 안내해 드립니다.





## 사전 요구 사항

아직 확인하지 않으셨다면, 계속하기 전에 [C2C 구현: 설정](./implementing-c2c-setting-up) 가이드를 검토해 주세요. [인증 및 권한 부여 과정](./implementing-c2c-authentication-and-authorization)에서 획득한 `access_token`이 필요합니다. 이 가이드에서는 [이 Frame.io 링크](https://f.io/Rq1q5CzB)에서 사용할 수 있는 샘플 테스트 에셋을 사용할 것입니다. 저희의 예제를 따라 할 수 있도록 이 파일을 다운로드하세요. 이렇게 하면 샘플 명령의 값을 맞출 수 있습니다.

## 1단계: 에셋 생성하기

[샘플 파일](https://f.io/Rq1q5CzB)을 업로드해 보겠습니다. 10초 전에 생성된 파일이라고 가정합니다. 먼저 Frame.io에 에셋 참조를 생성해야 합니다.

```shell
{
curl -X POST https://api.frame.io/v2/devices/assets \
    --header 'Authorization: Bearer [access_token]' \
    --header 'Content-Type: application/json' \
    --header 'x-client-version: 2.0.0' \
    --data-binary @- <<'__JSON__' 
        {
            "name": "C2C_TEST_CLIP.mp4", 
            "filetype": "video/mp4", 
            "filesize": 21136250,
            "offset": 10
        }
__JSON__
} | python -m json.tool
```




<Info title="API 엔드포인트 사양">
  `/v2/devices/assets`에 대한 문서는 [여기에서 확인](/camera-to-cloud/api-reference/device-asset-create)할 수 있습니다. 이전 엔드포인트 `/v2/assets`도 여전히 작동하지만, 새로운 통합에는 `/v2/devices/assets`를 사용하는 것이 좋습니다.
</Info>

<Info title="JSON 인코딩">
  이전에 사용했던 인증 엔드포인트와 달리, 이 엔드포인트는 `form/multipart` 대신 `application/json` 인코딩을 허용합니다. 또한 `application/x-www-form-urlencoded`도 허용합니다.
</Info>

<Info title="명령어 구문">
  이 예제에서는 가독성을 높이기 위해 여러 줄 형식으로 JSON 페이로드를 `curl`에 제공하기 위해 [heredoc](https://linuxize.com/post/bash-heredoc/)을 사용합니다. `--data-binary @-` 매개변수는 `curl`에 stdin에서 원시 데이터를 읽도록 지시합니다. 이 접근 방식에 대해 자세히 알아보려면 [여기](https://unix.stackexchange.com/questions/88490/how-do-you-use-output-redirection-in-combination-with-here-documents-and-cat)를 참조하세요.
</Info>


JSON 페이로드 매개변수를 살펴보겠습니다.

`name`: Frame.io에 표시되는 에셋 이름입니다. 디스크의 파일 이름과 일치할 필요는 없습니다. `filetype`: 파일의 [MIME 유형](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)입니다. 대부분의 프로그래밍 언어는 MIME 유형 감지를 위한 유틸리티를 제공합니다(예: [Go](https://golangcode.com/get-the-content-type-of-file/), [Python](https://docs.python.org/3/library/mimetypes.html)). `filesize`: 바이트 단위의 파일 크기입니다. 저희 샘플 파일은 약 21.1MB입니다. `offset`: 파일이 생성된 이후 지난 시간(초)입니다. 생략할 경우 기본값은 0입니다. 이 매개변수는 디바이스 일시 중지로 인해 파일을 거부해야 하는지 결정하는 데 도움이 되므로 반드시 제공해야 합니다. 이에 대한 자세한 내용은 [고급 업로드 가이드](./how-to-advanced-uploads)에서 다룰 예정입니다.

응답은 다음과 유사하게 보일 것입니다(일부 필드는 생략됨).





```json
{
    "_type": "file",
    ...
    "id": "9a280f99-8f4f-46b0-a4b4-ec4c2f95138e",
    ...
    "upload_urls": [
        "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_01_path]",
        "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_02_path]"
    ],
    ...
}
```





이 시점에서는 Frame.io에 파일 업로드 의도만 알렸을 뿐, 실제 파일 데이터는 전송되지 않았습니다. 프로젝트 내 디바이스의 폴더를 확인해 보면 &quot;업로드 중&quot; 상태인 자리 표시자 에셋이 보일 것입니다.

`upload_urls` 필드에는 파일 청크(chunk)를 업로드할 URL이 포함되어 있습니다. 저희 테스트 파일의 경우 두 개의 업로드 URL을 받아야 합니다.

## 2단계: 파일을 청크로 나누기





응답에는 여러 개의 업로드 URL이 포함되어 있었습니다. Frame.io에 업로드할 때 저희는 파일을 여러 청크로 나누어 개별적으로 업로드하며, 이는 다음과 같은 여러 이점을 제공합니다.




* **향상된 안정성**: 한 청크가 실패하더라도 전체 업로드를 다시 시작할 필요가 없습니다.
* **빠른 업로드**: 여러 청크를 병렬로 업로드할 수 있습니다([고급 업로드 가이드](./how-to-advanced-uploads)에서 다룸).




최적의 청크 크기를 결정하려면 다음 공식을 사용하세요.





**`Python`**

```python title="Python"
# We use math.ceil() to ensure we get the upper bound in the division
chunk_size = math.ceil(float(file.size) / float(len(response.upload_urls)))
```





샘플 파일의 경우 계산식은 다음과 같습니다.





**`Python`**

```python title="Python"
math.ceil(21136250 / 2)
# 10568125
```

이는 각 청크가 10,568,125바이트가 되어야 함을 의미합니다. 청크 크기는 일반적으로 25MB 정도를 목표로 하며, 정확한 계산은 [고급 업로드 가이드](./how-to-advanced-uploads)에서 다룹니다.
<Info title="마지막 청크 크기">
  파일 크기가 정확하게 나누어 떨어지는 경우는 드물기 때문에, 마지막 청크는 계산된 `chunk_size`보다 작을 수 있습니다. 구현 시 파일 청크를 읽을 때 이를 고려해야 합니다.
</Info>
 이 시연을 위해 [head](https://man7.org/linux/man-pages/man1/head.1.html) 및 [tail](https://man7.org/linux/man-pages/man1/tail.1.html) 명령을 사용하여 파일 청크를 추출해 보겠습니다.

## 3단계: 청크 업로드하기





첫 번째 청크를 업로드하려면:





```shell
head -c 10568125 ~/Downloads/C2C_TEST_CLIP.mp4 | \
curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_01_path] \
        --include \
        --header 'content-type: video/mp4' \
        --header 'x-amz-acl: private' \
        --data-binary @-
```




<Info title="명령어 구문">
  `--data-binary @-` 매개변수는 `curl`에 `head` 명령에서 나오는 stdin의 원시 데이터를 사용하도록 지시합니다.
</Info>


이 요청에는 다음 헤더가 필요합니다.

`content-type`: 에셋을 생성할 때 사용된 것과 동일한 MIME 유형 값 `x-amz-acl`: AWS S3 권한의 경우 항상 `private`으로 설정

성공적으로 업로드되면 다음이 반환됩니다.





```text
HTTP/1.1 100 Continue

HTTP/1.1 200 OK
...
```





동일한 방식으로 두 번째 청크를 업로드합니다.





```shell
tail -c 10568125 ~/Downloads/C2C_TEST_CLIP.mp4 | \
curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part_02_path] \
        --include \
        --header 'content-type: video/mp4' \
        --header 'x-amz-acl: private' \
        --data-binary @-
```





두 업로드가 모두 완료되면 에셋을 Frame.io에서 재생할 수 있습니다! 🎉




<Warning title="업로드 오류">
  청크를 업로드할 때는 Frame.io의 API가 아닌 AWS S3로 데이터를 직접 전송하는 것입니다. 따라서 오류 응답은 표준 Frame.io 오류 대신 AWS S3 형식을 따릅니다. S3 오류 처리에 대해서는 [오류 처리 가이드](/camera-to-cloud/how-to-handle-errors)에서 다루겠습니다.
</Warning>

<Info title="청크 순서">
  


순차적으로 청크를 업로드하는 것이 개념적으로는 더 간단하지만, 실제로는 순서에 상관없이 업로드할 수 있습니다. 시스템은 업로드 순서와 무관하게 청크를 올바르게 조립합니다.



</Info>


## 통합 기능





전체 업로드 프로세스에 대한 단순화된 Python 형식의 의사 코드(pseudocode) 예제는 다음과 같습니다.





**`Python`**

```python title="Python"
file = open("~/Downloads/C2C_TEST_CLIP.mp4")
mimetype = mimetypes.for_file("~/Downloads/C2C_TEST_CLIP.mp4")[0]
created_at = time.ctime(file.stat.ST_CTIME)

asset = c2c.asset_create(
    name="C2C_TEST_CLIP.mp4", 
    filetype=mimetype, 
    filesize=file.size,
    offset=datetime.now() - created_at,
    channel=0,
)

chunk_size = math.ceil(float(file.size) / float(len(asset.upload_urls)))

for chunk_url in asset.upload_urls:
   chunk = file.read(bytes=chunk_size)
   c2c.upload_chunk(chunk, chunk_url, mimetype)
```

이 예제는 오류 처리나 병렬 업로드가 없는 기본 흐름을 보여주며, 해당 내용은 [오류 처리](/camera-to-cloud/how-to-handle-errors) 및 [고급 업로드](./how-to-advanced-uploads) 가이드에서 다룰 예정입니다.

## 다음 단계

Frame.io에 첫 번째 에셋을 성공적으로 업로드하신 것을 축하합니다! [고급 업로드 가이드](./how-to-advanced-uploads)에서는 프로덕션 환경에 바로 적용할 수 있는 구현을 위한 더욱 정교한 기법과 요구 사항을 다룹니다. 궁금한 점이 있으실 경우 저희 팀에 문의해 주시길 바라며, [실시간 업로드 가이드](./how-to-upload-realtime)를 통해 에셋이 생성되는 즉시 업로드하는 방법에 대해 알아보시기 바랍니다.