Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function initialiseVideo(src) {
player.download = src;

$('#status').removeClass('d-flex').addClass('d-none');
$('#player').show();
$('#player').removeClass('d-none');

player.play();
}
Expand Down Expand Up @@ -87,8 +87,8 @@ function updateStatus(status) {
$('#status .fas').attr('class', 'fas fa-cloud-download-alt fa-2x');
$('#status p').text('IMPORTING FILE');
} else if (status === 'processing') {
$('#status .fas').attr('class', 'fas fa-server fa-2x');
$('#status p').text('PROCESSING');
$('#status .fas').attr('class', 'fas fa-cogs fa-2x');
$('#status p').text('CONVERTING');
} else if (status === 'ready') {
$('#status .fas').attr('class', 'fas fa-check-circle fa-2x');
$('#status p').text('READY');
Expand All @@ -112,7 +112,7 @@ function updateStatus(status) {
*/
function displayError(error) {
if (typeof error === 'string') {
$('#errors').text(error).removeClass('d-hide').addClass('d-block');
$('#errors').html(error).removeClass('d-hide').addClass('d-block');
return;
}

Expand All @@ -121,12 +121,12 @@ function displayError(error) {
if (error.status === 400) {
var response = error.responseJSON;
if (typeof response.data === 'string') {
$('#errors').text(response.data).removeClass('d-hide').addClass('d-block');
$('#errors').html(response.data).removeClass('d-hide').addClass('d-block');
} else {
$('#errors').text(unknownError).removeClass('d-hide').addClass('d-block');
$('#errors').html(unknownError).removeClass('d-hide').addClass('d-block');
}
} else {
$('#errors').text(unknownError).removeClass('d-hide').addClass('d-block');
$('#errors').html(unknownError).removeClass('d-hide').addClass('d-block');
}
}

Expand All @@ -136,7 +136,7 @@ function displayError(error) {
function resetErrors() {
$('input, label, select').removeClass('text-danger is-invalid');
$('.invalid-feedback').remove();
$('#errors').text('').removeClass('d-block').addClass('d-none');
$('#errors').html('').removeClass('d-block').addClass('d-none');
}

/**
Expand All @@ -158,7 +158,7 @@ function resetVideo() {
progress = 0;

$('.json-container').html('');
$('#json').hide();
$('#json').addClass('d-none');
}

/**
Expand Down Expand Up @@ -237,7 +237,7 @@ function prettyPrintJson(obj) {
* @param json
*/
function initialiseJson(json) {
$('#json').show();
$('#json').removeClass('d-none');
$('.json-container').html(prettyPrintJson(json));
}

Expand Down Expand Up @@ -354,6 +354,11 @@ function uploadFileToS3(file, presignedPostData, element) {
var $filePlaceholder = $parent.children('.file-placeholder');
var $filePlaceholderName = $filePlaceholder.children('.name');

if (file.size > 262144000) {
displayError('File size exceeds 250MB limit. <a href="https://dashboard.shotstack.io/register" target="_blank" class="text-brand">Sign up to use the API</a> to convert larger files.');
return;
}

var formData = new FormData();
Object.keys(presignedPostData.fields).forEach((key) => {
formData.append(key, presignedPostData.fields[key]);
Expand Down
186 changes: 169 additions & 17 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@
<meta name="robots" content="noindex">

<link
rel="stylesheet"
rel="preload"
href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@300;600&family=Kanit:wght@600&display=swap"
as="style"
onload="this.onload=null;this.rel='stylesheet'"
/>
<noscript>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@300;600&family=Kanit:wght@600&display=swap"
/>
</noscript>
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
Expand All @@ -30,24 +38,57 @@
<link rel="stylesheet" href="https://shotstack.io/assets/css/main.css" />
<link rel="stylesheet" href="styles.css" />

<title>Convert MP4 to MOV Shotstack Demo</title>
<title>MP4 to MOV Converter (Online & API) - Shotstack</title>
<meta
name="description"
content="Convert an MP4 video to MOV format using the Shotstack Ingest API. This demo shows you how to upload a video and convert it."
content="Convert MP4 to MOV online for free. Upload a file or paste a URL, preview, and download your MOV. Open-source demo powered by Shotstack Ingest API."
/>
<link rel="canonical" href="https://shotstack.io/demo/mp4-to-mov/" />

<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "MP4 to MOV Converter",
"url": "https://shotstack.io/demo/mp4-to-mov/",
"applicationCategory": "Multimedia",
"operatingSystem": "Web",
"description": "Use our free demo to convert MP4 to MOV online in minutes - ideal for QuickTime and editing tools. Works with all browsers. This demo is developed using the Shotstack Ingest API.",
"provider": {
"@type": "Organization",
"name": "Shotstack"
},
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD",
"description": "Free tier"
},
"potentialAction": {
"@type": "Action",
"name": "Convert Video",
"description": "Convert MP4 video to MOV format",
"target": "https://shotstack.io/demo/mp4-to-mov/"
}
}
</script>
</head>
<body>
<div class="container content my-4">
<header>
<h1 class="display-4">MP4 to MOV Converter</h1>
<p class="lead">Use our free demo to convert MP4 to MOV online in minutes - ideal for QuickTime and editing tools. Works with all browsers. This demo is developed using the Shotstack Ingest API.</p>
</header>
<div class="row">
<div class="col-5">
<div class="col-lg-5 mb-4 mb-lg-0">
<form class="jumbotron" method="post">
<div class="form-group video-group">
<label><b>Source video</b></label>
<small class="form-text text-muted float-right">
Max file size: 250MB
</small>
<div class="row mb-3">
<div class="col-6">
<div class="col-sm-6 col-12 mb-2 mb-sm-0">
<button
type="button"
class="btn btn-secondary w-100 upload-button toggle-button"
Expand All @@ -65,11 +106,11 @@
<i class="fas fa-upload upload-icon"></i> Upload
</button>
</div>
<div class="col-6">
<div class="col-sm-6 col-12">
<button
type="button"
class="btn btn-secondary w-100 url-button toggle-button"
data-toggle="collapse"
data-bs-toggle="collapse"
href="#urlExpand"
role="button"
aria-expanded="false"
Expand Down Expand Up @@ -122,14 +163,14 @@
</a>
</div>
</div>
<div class="col-7 video-container">
<div class="col-lg-7 video-container">
<div id="instructions" class="row justify-content-center align-items-center">
<div class="col-12 text-center jumbotron border">
<p>Your converted MP4 to MOV file will play here.</p>
</div>
</div>
<div id="status" class="row justify-content-center align-items-center d-none">
<div class="col-6 text-center">
<div class="col-sm-6 text-center">
<i class="fas fa-2x"></i>
<p></p>
<div class="progress" style="height: 2px">
Expand All @@ -141,11 +182,11 @@
aria-valuemax="100"
></div>
</div>
<small>Hold tight, processing may take a minute...</small>
<small>Hold tight, converting may take a minute...</small>
</div>
</div>
<video id="player" playsinline controls></video>
<div id="json" class="row">
<video id="player" playsinline controls class="d-none mb-0"></video>
<div id="json" class="row d-none mt-3">
<div class="col mt-4">
<p class="text-center">
<a
Expand All @@ -159,7 +200,7 @@
</a>
<a
class="btn btn-primary ml-2"
data-toggle="collapse"
data-bs-toggle="collapse"
href="#jsonExpand"
role="button"
aria-expanded="false"
Expand All @@ -177,16 +218,127 @@
</div>
</div>
</div>

<div class="row mt-5">
<div class="col-12">
<h2 class="h3 text-brand fw-bold mb-3">How to convert MP4 to MOV?</h2>
<p><strong>Step 1:</strong> Upload a video or paste a link/URL.</p>
<p><strong>Step 2:</strong> Click the convert video button to start your MP4 to MOV process.</p>
<p><strong>Step 3:</strong> Your MOV file will be available for preview and download after processing. Enjoy!</p>
</div>
</div>

<div class="row mt-4">
<div class="col-12">
<h2 class="h3 text-brand fw-bold mb-3">About MP4 and MOV (what changes when you convert)</h2>
<p>MP4 and MOV are both video containers. MP4 is widely used for web delivery; MOV is Apple's QuickTime container and is common in editing workflows. Converting MP4→MOV changes the container format. This demo uses the best approach: if your source codec is MOV-compatible, it copies without re-encoding; otherwise, it converts to H.264 for broad compatibility. Audio is handled similarly to ensure compatibility with QuickTime and most editors.</p>
</div>
</div>

<div class="row mt-4">
<div class="col-12">
<h2 class="h3 text-brand fw-bold mb-3">When to use MOV instead of MP4</h2>
<p>Choose MOV when you need maximum compatibility with Apple tools (QuickTime, Final Cut Pro) or when a client or editor specifically requests a .mov. For general web playback and smaller files, MP4 is usually the better choice. If your goal is simple viewing or sharing online, keep MP4; if your workflow involves QuickTime-centric review or handoff to an editor, use MOV.</p>
</div>
</div>

<div class="row mt-4">
<div class="col-12">
<h2 class="h3 text-brand fw-bold mb-3">Privacy & security</h2>
<p>Files are securely transferred over HTTPS and stored temporarily only to complete your conversion. We automatically delete source files and outputs shortly after processing. Your content is not used to train models.</p>
<p>The open-source code for this project is available on <a href="https://github.com/shotstack/mp4-to-mov-demo" target="_blank">GitHub</a>. It can serve as a foundation for anyone looking to create their own automated media conversion tool.</p>
</div>
</div>

<div class="row mt-4">
<div class="col-12">
<h2 class="h3 text-brand fw-bold mb-3">Do more with Shotstack (for frequent conversions)</h2>
<p>If you only need the occasional MP4→MOV, this demo is perfect. If you're converting lots of files, or need editor-friendly outputs on a schedule, <a href="https://shotstack.io/product/video-editing-api/" target="_blank">Shotstack's APIs</a> can automate it - queue jobs, process at scale, receive webhooks when they finish, and deliver files via CDN.</p>
<p><a href="https://dashboard.shotstack.io/register" target="_blank">Sign up</a> and get started for free (no credit card needed).</p>
</div>
</div>

<div class="row mt-4">
<div class="col-12">
<h2 class="h3 text-brand fw-bold mb-4 pb-2 section-divider">Frequently asked questions (FAQs)</h2>

<div class="accordion faq-accordion" id="faqAccordion">
<div class="accordion-item">
<h3 class="accordion-header">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#faq1" aria-expanded="true" aria-controls="faq1">
Does converting MP4 to MOV improve video quality?
</button>
</h3>
<div id="faq1" class="accordion-collapse collapse show" data-bs-parent="#faqAccordion">
<div class="accordion-body">
No - changing containers doesn't increase quality. This demo automatically copies your source codec if it's compatible with MOV, or converts to H.264 if needed. Quality depends on your source file and what conversion (if any) occurs.
</div>
</div>
</div>

<div class="accordion-item">
<h3 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faq2" aria-expanded="false" aria-controls="faq2">
Can I get a ProRes MOV from this demo?
</button>
</h3>
<div id="faq2" class="accordion-collapse collapse" data-bs-parent="#faqAccordion">
<div class="accordion-body">
The demo outputs a MOV file with the same codec as the source video. If the codec is incompatible it will default to H.264.
</div>
</div>
</div>

<div class="accordion-item">
<h3 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faq3" aria-expanded="false" aria-controls="faq3">
Can I convert MP4 to MOV from a Google Drive/Dropbox link?
</button>
</h3>
<div id="faq3" class="accordion-collapse collapse" data-bs-parent="#faqAccordion">
<div class="accordion-body">
Use a direct download URL. If the link requires you to be logged in or expires quickly, download the file locally and upload it here.
</div>
</div>
</div>

<div class="accordion-item">
<h3 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faq4" aria-expanded="false" aria-controls="faq4">
What's the file size limit?
</button>
</h3>
<div id="faq4" class="accordion-collapse collapse" data-bs-parent="#faqAccordion">
<div class="accordion-body">
250MB per file in the demo. For larger files or batches, use the Shotstack Ingest API directly.
</div>
</div>
</div>

<div class="accordion-item">
<h3 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faq5" aria-expanded="false" aria-controls="faq5">
Is MOV better for Final Cut or QuickTime?
</button>
</h3>
<div id="faq5" class="accordion-collapse collapse" data-bs-parent="#faqAccordion">
<div class="accordion-body">
MOV is the native QuickTime container and works well in Apple tools. For simple playback or web delivery, MP4 is typically smaller. Choose based on your workflow.
</div>
</div>
</div>
</div>
</div>
</div>

</div>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"
></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src="https://cdn.plyr.io/3.7.8/plyr.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.5.4/umd/popper.min.js"></script>
<script src="app.js"></script>
</body>
</html>
Loading