Converting media files — and adjusting individual stream characteristics within them — is handled by two command-line tools: Shaka Packager and FFmpeg. The two are not interchangeable feature-for-feature. Where a procedure has no equivalent in one of them, that's noted below.

Most of the commands shown here would normally be combined into a single invocation — setting a bitrate at the same time as converting a file, for instance. They're written separately here purely for clarity.

Inspecting a file

Both tools can report the characteristics of the streams inside a media file, though their output for the same input differs.

With Shaka Packager:

packager input=glocken.mp4 --dump_stream_info

This produces output like:

File "glocken.mp4":
Found 2 stream(s).
Stream [0] type: Video
 codec_string: avc1.640028
 time_scale: 30000
 duration: 300300 (10.0 seconds)
 is_encrypted: false
 codec: H264
 width: 1920
 height: 1080
 pixel_aspect_ratio: 1:1
 trick_play_factor: 0
 nalu_length_size: 4

Stream [1] type: Audio
 codec_string: mp4a.40.2
 time_scale: 48000
 duration: 481280 (10.0 seconds)
 is_encrypted: false
 codec: AAC
 sample_bits: 16
 num_channels: 2
 sampling_frequency: 48000
 language: eng
 seek_preroll_ns: 20833

With FFmpeg:

ffmpeg -i glocken.mp4

This produces output like:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'glocken.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf57.83.100
  Duration: 00:00:10.03, start: 0.000000, bitrate: 8063 kb/s
    Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc), 1920x1080, 7939 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 127 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
At least one output file must be specified

Splitting and rejoining streams

Shaka Packager requires demuxing before it will convert files, and demuxing is likewise required when working with media frameworks.

Demuxing

MP4

packager input=myvideo.mp4,stream=video,output=myvideo_video.mp4
packager input=myvideo.mp4,stream=audio,output=myvideo_audio.m4a

Or:

packager \
  input=myvideo.mp4,stream=video,output=myvideo_video.mp4 \
  input=myvideo.mp4,stream=audio,output=myvideo_audio.m4a

WebM

packager \
  input=myvideo.webm,stream=video,output=myvideo_video.webm \
  input=myvideo.webm,stream=audio,output=myvideo_audio.webm

The same separation in FFmpeg, for MP4:

ffmpeg -i myvideo.mp4 -vcodec copy -an myvideo_video.mp4
ffmpeg -i myvideo.mp4 -acodec copy -vn myvideo_audio.m4a

and for WebM:

ffmpeg -i myvideo.webm -vcodec copy -an myvideo_video.webm
ffmpeg -i myvideo.webm -acodec copy -vn myvideo_audio.webm

Remuxing

Putting audio and video back into a single container is occasionally necessary, particularly when a media framework isn't in use. FFmpeg handles this well; Shaka Packager does not currently support it.

ffmpeg -i myvideo_video.webm -i myvideo_audio.webm -c copy myvideo.webm

Altering stream characteristics

Bitrate

FFmpeg can set the bitrate during conversion to .mp4 or .webm.

ffmpeg -i myvideo.mov -b:v 350K myvideo.mp4
ffmpeg -i myvideo.mov -vf setsar=1:1 -b:v 350K myvideo.webm

Resolution

ffmpeg -i myvideo.webm -s 1920x1080 myvideo_1920x1080.webm

Changing the container format

Because Shaka Packager can't process .mov files, it can't convert from that format; FFmpeg can.

.mov to .mp4

ffmpeg -i myvideo.mov myvideo.mp4

.mov to .webm

ffmpeg -i myvideo.mov myvideo.webm

Keyframes for A/V sync

Inserting keyframes keeps audio and video in sync during playback.

ffmpeg -i myvideo.mp4 -keyint_min 150 -g 150 -f webm -vf setsar=1:1 out.webm

MP4/H.264

ffmpeg -i myvideo.mp4 -c:v libx264 -c:a copy myvideo.mp4

Audio for an MP4

ffmpeg -i myvideo.mp4 -c:v copy -c:a aac myvideo.mp4

WebM/VP9

ffmpeg -i myvideo.webm -v:c libvpx-vp9 -v:a copy myvideo.webm

Audio for a WebM

ffmpeg -i myvideo.webm -v:c copy -v:a libvorbis myvideo.webm
ffmpeg -i myvideo.webm -v:c copy -v:a libopus myvideo.webm

Streaming output

Two streaming protocols are covered here. Dynamic Adaptive Streaming over HTTP (DASH) is an adaptive bitrate, web-standards-based technique for video-on-demand. HTTP Live Streaming (HLS) is Apple's standard for live streaming and video-on-demand on the web.

DASH

The following generates a Media Presentation Description (MPD) output file from the audio and video streams.

packager \
  input=myvideo.mp4,stream=audio,output=myvideo_audio.mp4 \
  input=myvideo.mp4,stream=video,output=myvideo_video.mp4 \
  --mpd_output myvideo_vod.mpd

HLS

These examples produce an M3U8 output file — a UTF-8 encoded multimedia playlist — from the audio and video streams.

ffmpeg -i myvideo.mp4 -c:a copy -b:v 8M -c:v copy -f hls \
  -hls_time 10 -hls_list_size 0 myvideo.m3u8

Or:

packager \
  'input=myvideo.mp4,stream=video,segment_template=output$Number$.ts,playlist_name=video_playlist.m3u8' \
  'input=myvideo.mp4,stream=audio,segment_template=output_audio$Number$.ts,playlist_name=audio_playlist.m3u8,hls_group_id=audio,hls_name=ENGLISH' \
  --hls_master_playlist_output="master_playlist.m3u8"