<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Video requirements for the zConnect Gallery</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Inter+Tight:wght@400;500;600;700;800&display=swap" rel="stylesheet"> <style> :root { --ink: #000000; --paper: #FFFFFF; --lime: #AFF44A; --lav: #D5B3FF; --mist: #F4F4F1; --rule: #E3E3DF; --muted: #5C5C58; --red: #C9352B; } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; background: var(--paper); } body { font-family: "Inter Tight", "Helvetica Neue", Arial, sans-serif; color: var(--ink); font-size: 17px; line-height: 1.55; -webkit-font-smoothing: antialiased; } .kb { max-width: 920px; margin: 0 auto; padding: 40px 24px 64px; } p { margin: 0 0 1em; } p:last-child { margin-bottom: 0; } a { color: var(--ink); text-decoration-thickness: 2px; text-underline-offset: 3px; } a:hover { text-decoration-color: var(--lime); } :focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; border-radius: 2px; } code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 0.92em; background: var(--mist); padding: 2px 6px; border-radius: 4px; } /* ---------- Hero ---------- */ .hero { display: flex; flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: clamp(24px, 5%, 48px); padding-bottom: 56px; } .hero-copy { flex: 3 1 280px; min-width: 0; } h1 { font-size: clamp(38px, 6vw, 60px); line-height: 1.02; font-weight: 800; letter-spacing: -0.025em; margin: 0 0 28px; } h2 { font-size: 30px; line-height: 1.15; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 20px; } h3 { font-size: 21px; line-height: 1.25; font-weight: 700; letter-spacing: -0.01em; margin: 0 0 10px; } /* Checklist */ .specs { list-style: none; margin: 0; padding: 0; } .specs li { display: grid; grid-template-columns: 28px 1fr; gap: 14px; align-items: start; padding: 12px 0; border-top: 1px solid var(--rule); font-size: 19px; font-weight: 500; } .specs li:last-child { border-bottom: 1px solid var(--rule); } .specs li small { display: block; font-size: 15px; font-weight: 400; color: var(--muted); margin-top: 2px; } .tick { width: 28px; height: 28px; background: var(--lime); border-radius: 6px; display: grid; place-items: center; margin-top: 1px; } .tick svg { width: 16px; height: 16px; display: block; } /* Device with a screen inside; the dimension lines measure the screen */ .frame-wrap { flex: 1 1 220px; min-width: 170px; max-width: 300px; } .frame-box { position: relative; padding: 40px 48px 0 0; } .device { position: relative; background: #1A1A1A; border-radius: 16px; padding: 24px 11px 36px; box-shadow: inset 0 0 0 1px #3A3A3A; } .device .cam { position: absolute; top: 9px; left: 50%; width: 6px; height: 6px; margin-left: -3px; border-radius: 50%; background: #050505; box-shadow: inset 0 0 0 1px #4A4A4A; } .screen { position: relative; width: 100%; aspect-ratio: 600 / 1024; background: #000; border-radius: 3px; box-shadow: 0 0 0 1px #3A3A3A; display: grid; place-items: center; } .screen .play { width: 64px; height: 64px; border-radius: 50%; background: var(--lime); display: grid; place-items: center; } .screen .play svg { width: 22px; height: 22px; margin-left: 4px; } .screen .fps { position: absolute; left: 14px; bottom: 12px; color: var(--paper); font-size: 13px; font-weight: 500; opacity: .85; } .screen .fps b { color: var(--lime); font-weight: 700; } /* Dimension lines hang off the screen box, so they line up with the screen edges */ .dim-x, .dim-y { position: absolute; font-size: 13px; font-weight: 600; color: var(--ink); } .dim-x { top: -66px; left: 0; right: 0; height: 22px; display: flex; align-items: center; justify-content: center; } .dim-x::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; border-top: 1px solid var(--ink); } .dim-x::after { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 10px; transform: translateY(-50%); border-left: 1px solid var(--ink); border-right: 1px solid var(--ink); } .dim-x span, .dim-y span { position: relative; z-index: 1; background: var(--paper); padding: 0 8px; } .dim-y { top: 0; bottom: 0; right: -48px; width: 22px; display: flex; align-items: center; justify-content: center; } .dim-y::before { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; border-left: 1px solid var(--ink); } .dim-y::after { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 10px; transform: translateX(-50%); border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink); } .dim-y span { writing-mode: vertical-rl; padding: 8px 0; } .frame-caption { font-size: 14px; color: var(--muted); margin-top: 12px; padding-right: 48px; } /* ---------- Sections ---------- */ .sec { padding: 48px 0 56px; border-top: 2px solid var(--ink); } .sec:last-child { padding-bottom: 0; } .prose { max-width: 40em; } /* Error toast recreation */ .toast { position: relative; display: grid; grid-template-columns: 34px 1fr; gap: 18px; align-items: center; background: var(--red); color: var(--paper); border-radius: 10px; padding: 26px 56px 26px 26px; font-size: 19px; line-height: 1.4; max-width: 560px; margin: 0 0 28px; box-shadow: 0 6px 24px rgba(201,53,43,.22); } .toast .x { width: 34px; height: 34px; border-radius: 50%; background: var(--paper); display: grid; place-items: center; } .toast .x svg { width: 16px; height: 16px; } .toast .close { position: absolute; right: 18px; top: 14px; font-size: 22px; font-weight: 700; line-height: 1; } .good-news { background: var(--lav); border-radius: 12px; padding: 20px 24px; font-size: 18px; font-weight: 500; max-width: 40em; margin: 0 0 28px; } /* File diagram */ .files { display: grid; gap: 28px; margin: 36px 0 8px; } .file { background: var(--mist); border-radius: 14px; padding: 22px 24px 20px; } .file h3 { font-size: 18px; margin-bottom: 14px; } .bar { position: relative; display: flex; gap: 3px; height: 46px; } .seg { display: grid; place-items: center; font-size: 13px; font-weight: 600; border-radius: 7px; white-space: nowrap; overflow: hidden; } .seg.video { flex: 1 1 auto; background: var(--ink); color: var(--paper); } .seg.codec { flex: 0 0 var(--codec-w); background: var(--lime); color: var(--ink); } .bar { --codec-w: 15%; } /* Dashed box = the first 2 MB. Sized to the codec block so the two line up exactly. */ .scan { position: absolute; left: -7px; top: -8px; bottom: -8px; width: calc(var(--codec-w) + 14px); border: 2px dashed var(--ink); border-radius: 10px; pointer-events: none; } .scan-label { display: flex; align-items: center; gap: 8px; margin-top: 14px; font-size: 14px; color: var(--ink); padding-left: 2px; } .scan-label::before { content: ""; flex: 0 0 14px; height: 0; border-top: 2px dashed var(--ink); } .verdict { margin-top: 12px; font-size: 15px; font-weight: 600; } .verdict.bad { color: var(--red); } .verdict.ok { color: #2E7D1F; } /* Fix options */ .options { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); align-items: start; gap: 24px; margin-top: 28px; } .option { min-width: 0; border: 2px solid var(--ink); border-radius: 16px; padding: 26px 26px 24px; } .option .tag { display: inline-block; background: var(--lime); font-size: 14px; font-weight: 700; padding: 4px 10px; border-radius: 999px; margin-bottom: 14px; } .option p { font-size: 16px; } .names { list-style: none; padding: 0; margin: 14px 0 0; display: flex; flex-wrap: wrap; gap: 8px; } .names li { border: 1.5px solid var(--ink); border-radius: 999px; padding: 5px 12px; font-size: 14px; font-weight: 600; } .names li em { font-style: normal; font-weight: 400; color: var(--muted); } ol.steps { margin: 14px 0 0; padding: 0; list-style: none; counter-reset: step; } ol.steps li { counter-increment: step; position: relative; padding: 0 0 14px 38px; font-size: 16px; } ol.steps li::before { content: counter(step); position: absolute; left: 0; top: 0; width: 26px; height: 26px; border-radius: 50%; background: var(--ink); color: var(--lime); font-size: 13px; font-weight: 700; display: grid; place-items: center; } ol.steps li:last-child { padding-bottom: 0; } pre { margin: 10px 0 0; background: var(--ink); color: var(--paper); border-radius: 10px; padding: 14px 16px; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 13.5px; line-height: 1.55; overflow-x: auto; white-space: pre-wrap; overflow-wrap: break-word; } .dumps pre { font-size: 12.5px; white-space: pre; } pre .hl { color: var(--lime); white-space: nowrap; } pre .nb { white-space: nowrap; } pre .c { color: #A9A9A4; } .note { font-size: 15px; color: var(--muted); margin-top: 12px; } /* Under the hood */ .dumps { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: 20px; margin-top: 20px; max-width: 720px; } .dumps > div { min-width: 0; } .dumps h4 { margin: 0 0 8px; font-size: 15px; font-weight: 600; } /* ---------- Responsive ---------- */ @media (max-width: 700px) { h2 { font-size: 26px; } .toast { font-size: 17px; padding: 22px 48px 22px 20px; } .bar { --codec-w: 26%; } } </style> </head> <body> <div class="kb"> <!-- ================= HERO ================= --> <div class="hero"> <div class="hero-copy"> <h1>Getting Your Video <span style="white-space:nowrap">Ziosk-Ready</span></h1> <ul class="specs"> <li> <span class="tick"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8.5l3.2 3L13 4.5" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span> <span>.MP4 file format<small>No .MOV, .AVI, or .WMV.</small></span> </li> <li> <span class="tick"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8.5l3.2 3L13 4.5" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span> <span>H.264/AVC video codec</span> </li> <li> <span class="tick"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8.5l3.2 3L13 4.5" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span> <span>24 frames per second</span> </li> <li> <span class="tick"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8.5l3.2 3L13 4.5" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span> <span>600 x 1024 pixels<small>Portrait, like the tablet.</small></span> </li> <li> <span class="tick"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8.5l3.2 3L13 4.5" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span> <span>Fast start turned on<small>The sneaky one. Details below.</small></span> </li> </ul> </div> <div class="frame-wrap" aria-hidden="true"> <div class="frame-box"> <div class="device"> <div class="cam"></div> <div class="screen"> <div class="dim-x"><span>600 px</span></div> <div class="dim-y"><span>1024 px</span></div> <div class="play"><svg viewBox="0 0 24 24" fill="#000"><path d="M6 4l14 8-14 8z"/></svg></div> <div class="fps"><b>24</b> fps</div> </div> </div> </div> <p class="frame-caption">600 x 1024 is the screen, not the whole device. Build it portrait from the start.</p> </div> </div> <!-- ================= THE ERROR ================= --> <div class="sec"> <h2>Seeing this error?</h2> <div class="toast" role="img" aria-label="zConnect error: Unable to detect video codec. The video may be corrupted. Please use H.264/AVC codec."> <span class="x"><svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8" stroke="#C9352B" stroke-width="2.6" stroke-linecap="round"/></svg></span> <span>Unable to detect video codec. The video may be corrupted. Please use H.264/AVC codec.</span> <span class="close" aria-hidden="true">&times;</span> </div> <div class="good-news">Good news: your video is almost certainly fine. Its codec information is just sitting in the wrong spot, and that takes about ten seconds to fix.</div> <div class="prose"> <p>Every MP4 carries a small block of codec information, a table of contents that tells the player how to read the video. Some editors save it at the very end of the file. zConnect only checks the first 2 MB, so if it isn't there, the upload gets flagged as corrupted even though every frame is intact.</p> <p>An export setting called <strong>fast start</strong> moves that table of contents to the front. Picture, sound, and quality stay exactly the same.</p> </div> <div class="files" aria-label="How zConnect reads an MP4 with and without fast start"> <div class="file"> <h3>Without fast start</h3> <div class="bar"> <div class="seg video">Video</div> <div class="seg codec">Codec info</div> <div class="scan"></div> </div> <div class="scan-label">zConnect only reads this far (2 MB)</div> <div class="verdict bad">Codec info never found. Error.</div> </div> <div class="file"> <h3>With fast start</h3> <div class="bar"> <div class="seg codec">Codec info</div> <div class="seg video">Video</div> <div class="scan"></div> </div> <div class="scan-label">zConnect only reads this far (2 MB)</div> <div class="verdict ok">Codec info found. Video uploads.</div> </div> </div> </div> <!-- ================= THE FIX ================= --> <div class="sec"> <h2>How to turn on fast start</h2> <div class="options"> <div class="option"> <span class="tag">Still have the project open?</span> <h3>Re-export with fast start on</h3> <p>Look for it in your export settings. Different tools call it different things:</p> <ul class="names"> <li>Fast start</li> <li>Web optimized <em>(HandBrake)</em></li> <li>Optimize for streaming</li> <li>Progressive download</li> </ul> <p class="note">Turn it on, export as .MP4 with H.264, done.</p> </div> <div class="option"> <span class="tag">Only have the finished .MP4?</span> <h3>Fix the file you already have</h3> <p>FFmpeg can move the codec information without touching the video.</p> <ol class="steps"> <li>Download FFmpeg (free) from <a href="https://ffmpeg.org" rel="noopener">ffmpeg.org</a>.</li> <li>Put <code>ffmpeg.exe</code> and your video in the same folder.</li> <li>Open a command prompt in that folder and run: <pre>ffmpeg -i <span class="hl">your-video.mp4</span> -c copy <span class="nb">-movflags +faststart</span> <span class="hl">your-video-fixed.mp4</span></pre> </li> <li>Upload <code>your-video-fixed.mp4</code> to the Gallery.</li> </ol> <p class="note">Swap in your own file names. Nothing gets re-encoded, so no quality loss.</p> </div> </div> </div> <!-- ================= UNDER THE HOOD ================= --> <div class="sec"> <h2>Curious what's actually happening inside the file?</h2> <div class="prose"> <p>MP4s are built from boxes. Codec info lives in <code>moov</code>, the video in <code>mdat</code>. Same file, before and after fast start:</p> </div> <div class="dumps"> <div> <h4>Before</h4> <pre>[ftyp] size=8+12 [wide] size=8+0 [mdat] size=8+6530124 <span class="c">video</span> <span class="hl">[moov] size=8+6645 codec info</span></pre> </div> <div> <h4>After fast start</h4> <pre>[ftyp] size=8+24 <span class="hl">[moov] size=8+5619 codec info</span> [free] size=8+0 [mdat] size=8+6464292 <span class="c">video</span></pre> </div> </div> </div> </div> </body> </html>