Article

How to Download MP4 Videos

File Extensions: .mp4, .m4v, .m4a MIME Types: video/mp4, audio/mp4 Container: Multimedia container Codecs: H.264, H.265, AAC, and many others

Devin Schumacher7 min read

File Extensions: .mp4, .m4v, .m4a
MIME Types: video/mp4, audio/mp4
Container: Multimedia container
Codecs: H.264, H.265, AAC, and many others

Overview

MP4 is a digital multimedia container format most commonly used to store video and audio, but can also store other data such as subtitles and still images. It's based on Apple's QuickTime File Format (.mov) and is defined by the ISO/IEC 14496-14 standard.

Structure

MP4 files use a hierarchical structure of "atoms" or "boxes":

ftyp (File Type Box)
mdat (Media Data Box)
moov (Movie Box)
  ├─ mvhd (Movie Header)
  ├─ trak (Track Box)
  │   ├─ tkhd (Track Header)
  │   ├─ mdia (Media Box)
  │   │   ├─ mdhd (Media Header)
  │   │   ├─ hdlr (Handler Reference)
  │   │   └─ minf (Media Information)
  │   └─ ...
  └─ ...

Detection Methods

1. File Extension and MIME Type

JAVASCRIPT
// Check file extension
function isMP4(filename) {
  return /\.(mp4|m4v|m4a)$/i.test(filename);
}

// Check MIME type
function isMP4MimeType(mimeType) {
  return /^(video|audio)\/mp4$/i.test(mimeType);
}

2. Network Traffic Analysis

JAVASCRIPT
// Browser Network monitoring
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    if (entry.name.includes('.mp4')) {
      console.log('MP4 detected:', entry.name);
    }
  });
});
observer.observe({ entryTypes: ['resource'] });

3. HTML Video Element Detection

JAVASCRIPT
// Find all video elements with MP4 sources
function findMP4Videos() {
  const videos = [];
  
  document.querySelectorAll('video').forEach(video => {
    // Check main src
    if (video.src && isMP4(video.src)) {
      videos.push({ element: video, src: video.src });
    }
    
    // Check source elements
    video.querySelectorAll('source').forEach(source => {
      if (source.src && isMP4(source.src)) {
        videos.push({ element: video, src: source.src, type: source.type });
      }
    });
  });
  
  return videos;
}

4. Binary File Header Detection

JAVASCRIPT
// Detect MP4 by file header (magic bytes)
async function detectMP4Header(arrayBuffer) {
  const view = new DataView(arrayBuffer);
  
  // Check for ftyp box at offset 4
  const ftyp = String.fromCharCode(
    view.getUint8(4), view.getUint8(5), view.getUint8(6), view.getUint8(7)
  );
  
  if (ftyp === 'ftyp') {
    // Check major brand
    const majorBrand = String.fromCharCode(
      view.getUint8(8), view.getUint8(9), view.getUint8(10), view.getUint8(11)
    );
    
    // Common MP4 brands
    const mp4Brands = ['isom', 'mp41', 'mp42', 'dash', 'msdh', 'msix', 'avc1'];
    return mp4Brands.includes(majorBrand);
  }
  
  return false;
}

// Usage with fetch
async function checkIfMP4(url) {
  const response = await fetch(url, { 
    method: 'HEAD',
    headers: { 'Range': 'bytes=0-31' }
  });
  
  const buffer = await response.arrayBuffer();
  return detectMP4Header(buffer);
}

Download Methods

1. Direct HTTP Download

BASH
# Simple wget download
wget "https://example.com/video.mp4"

# With custom headers
wget --header="Referer: https://example.com/" \
     --header="User-Agent: Mozilla/5.0..." \
     "https://example.com/video.mp4"

# Resume partial download
wget -c "https://example.com/video.mp4"

2. curl Download

BASH
# Basic download
curl -o video.mp4 "https://example.com/video.mp4"

# With headers
curl -H "Referer: https://example.com/" \
     -H "User-Agent: Mozilla/5.0..." \
     -o video.mp4 \
     "https://example.com/video.mp4"

# With progress bar
curl --progress-bar -o video.mp4 "https://example.com/video.mp4"

# Resume download
curl -C - -o video.mp4 "https://example.com/video.mp4"

3. yt-dlp for Complex Sources

BASH
# When MP4 is behind player logic
yt-dlp -f "mp4" "https://example.com/page-with-video"

# Force MP4 format
yt-dlp -f "best[ext=mp4]" "https://example.com/page-with-video"

# Merge video+audio to MP4
yt-dlp -f "bv*+ba/b" --merge-output-format mp4 "https://example.com/page"

4. Browser-Based Download

JAVASCRIPT
// Download MP4 from browser
async function downloadMP4(url, filename) {
  try {
    const response = await fetch(url);
    const blob = await response.blob();
    
    // Create download link
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = filename;
    a.click();
    
    // Cleanup
    URL.revokeObjectURL(a.href);
  } catch (error) {
    console.error('Download failed:', error);
  }
}

// Usage
downloadMP4('https://example.com/video.mp4', 'downloaded_video.mp4');

5. Node.js Download with Progress

JAVASCRIPT
const fs = require('fs');
const https = require('https');

function downloadMP4(url, outputPath) {
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(outputPath);
    
    https.get(url, (response) => {
      const totalSize = parseInt(response.headers['content-length'], 10);
      let downloadedSize = 0;
      
      response.on('data', (chunk) => {
        downloadedSize += chunk.length;
        const progress = ((downloadedSize / totalSize) * 100).toFixed(2);
        process.stdout.write(`\rDownload progress: ${progress}%`);
      });
      
      response.pipe(file);
      
      file.on('finish', () => {
        file.close();
        console.log('\nDownload completed!');
        resolve();
      });
      
      file.on('error', reject);
    }).on('error', reject);
  });
}

Progressive Download Detection

1. Range Request Support

JAVASCRIPT
// Check if server supports partial content
async function supportsRangeRequests(url) {
  const response = await fetch(url, {
    method: 'HEAD'
  });
  
  return response.headers.get('accept-ranges') === 'bytes' ||
         response.headers.get('content-range') !== null;
}

// Download with range requests
async function downloadWithRanges(url, chunkSize = 1024 * 1024) {
  const response = await fetch(url, { method: 'HEAD' });
  const totalSize = parseInt(response.headers.get('content-length'));
  
  const chunks = [];
  
  for (let start = 0; start < totalSize; start += chunkSize) {
    const end = Math.min(start + chunkSize - 1, totalSize - 1);
    
    const chunkResponse = await fetch(url, {
      headers: { 'Range': `bytes=${start}-${end}` }
    });
    
    const chunk = await chunkResponse.arrayBuffer();
    chunks.push(chunk);
    
    console.log(`Downloaded ${end + 1}/${totalSize} bytes`);
  }
  
  // Combine chunks
  const totalBuffer = new Uint8Array(totalSize);
  let offset = 0;
  
  chunks.forEach(chunk => {
    totalBuffer.set(new Uint8Array(chunk), offset);
    offset += chunk.byteLength;
  });
  
  return totalBuffer;
}

Metadata Extraction

1. Basic MP4 Information

JAVASCRIPT
// Extract basic MP4 metadata using File API
async function extractMP4Metadata(file) {
  const buffer = await file.arrayBuffer();
  const view = new DataView(buffer);
  
  let offset = 0;
  const boxes = [];
  
  while (offset < buffer.byteLength - 8) {
    const size = view.getUint32(offset, false);
    const type = String.fromCharCode(
      view.getUint8(offset + 4),
      view.getUint8(offset + 5),
      view.getUint8(offset + 6),
      view.getUint8(offset + 7)
    );
    
    boxes.push({ type, size, offset });
    
    if (size === 0) break;
    offset += size;
  }
  
  return boxes;
}

2. Using ffprobe

BASH
# Extract detailed metadata
ffprobe -v quiet -print_format json -show_format -show_streams video.mp4

# Get duration only
ffprobe -v quiet -show_entries format=duration -of csv="p=0" video.mp4

# Get resolution
ffprobe -v quiet -select_streams v:0 -show_entries stream=width,height -of csv="s=x:p=0" video.mp4

Container Analysis and Conversion

1. Check MP4 Compatibility

BASH
# Check if MP4 is web-compatible
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of csv="p=0" video.mp4

# Check for faststart (moov atom at beginning)
ffprobe -v error -show_entries format=format_name -of csv="p=0" video.mp4

2. Optimize MP4 for Web

BASH
# Move moov atom to beginning for streaming
ffmpeg -i input.mp4 -c copy -movflags +faststart output.mp4

# Convert to web-compatible format
ffmpeg -i input.mp4 \
       -c:v libx264 -preset medium -crf 23 \
       -c:a aac -b:a 128k \
       -movflags +faststart \
       output.mp4

3. Fragment MP4 (for DASH/HLS)

BASH
# Create fragmented MP4
ffmpeg -i input.mp4 -c copy -f mp4 -movflags frag_keyframe+empty_moov output.mp4

Advanced Detection Techniques

1. Progressive Web App Integration

JAVASCRIPT
// Service Worker to intercept MP4 requests
self.addEventListener('fetch', event => {
  const url = event.request.url;
  
  if (url.includes('.mp4') || event.request.headers.get('accept')?.includes('video/mp4')) {
    console.log('MP4 request intercepted:', url);
    
    // You can modify the request or response here
    event.respondWith(
      fetch(event.request).then(response => {
        console.log('MP4 response:', response);
        return response;
      })
    );
  }
});

2. Media Source Extension (MSE) Detection

JAVASCRIPT
// Detect MP4 being fed to MSE
if ('MediaSource' in window) {
  const originalAppendBuffer = SourceBuffer.prototype.appendBuffer;
  
  SourceBuffer.prototype.appendBuffer = function(buffer) {
    // Check if buffer contains MP4 data
    if (detectMP4Header(buffer)) {
      console.log('MP4 data appended to MSE');
    }
    
    return originalAppendBuffer.call(this, buffer);
  };
}

Common Issues and Solutions

1. CORS Issues

JAVASCRIPT
// Proxy approach for CORS-restricted MP4
const proxyUrl = 'https://cors-anywhere.herokuapp.com/';
const mp4Url = 'https://example.com/video.mp4';

fetch(proxyUrl + mp4Url)
  .then(response => response.blob())
  .then(blob => {
    const url = URL.createObjectURL(blob);
    // Use the blob URL
  });

2. Large File Handling

JAVASCRIPT
// Stream large MP4 files
async function streamMP4Download(url) {
  const response = await fetch(url);
  const reader = response.body.getReader();
  
  while (true) {
    const { done, value } = await reader.read();
    
    if (done) break;
    
    // Process chunk
    console.log('Received chunk:', value.length);
  }
}

3. Authentication Issues

BASH
# Download with authentication
curl -H "Authorization: Bearer TOKEN" \
     -o video.mp4 \
     "https://api.example.com/video.mp4"

# Using cookies
curl -b cookies.txt \
     -o video.mp4 \
     "https://example.com/video.mp4"

Platform-Specific Considerations

YouTube

  • Often uses DASH segments, but fallback MP4 available
  • Requires extraction via yt-dlp

Vimeo

  • Progressive MP4 download available for some videos
  • HLS/DASH preferred for adaptive streaming

Wistia

  • Direct MP4 URLs often available
  • Multiple quality variants

Social Media Platforms

  • MP4 usually embedded in page data
  • May require API access or scraping

Standard: ITU-T H.265 / ISO/IEC HEVC Also Known As: HEVC (High Efficiency Video Coding) File Extensions: .h265, .265, .hevc Containers: MP4, MKV, MOV, TS...

Read article

Developer: Google Standard: VP9 (WebM Project) File Extensions: .vp9, .webm Containers: WebM, MKV MIME Types: video/webm; codecs="vp9"

Read article

Step-by-step Loom download guide with yt-dlp covering share links, embeds, separate streams, and ready-to-copy command cheat sheets.

Read article