MMS Transcoding
June 12, 2026 · View on GitHub
This document covers the MMS media normalization pipeline in GOMSGGW.
Overview
GOMSGGW includes an intelligent transcoding system to ensure MMS messages are deliverable across all carrier networks and handset types. The system automatically processes media files to meet carrier-specific size and format requirements.
flowchart LR
IN[Incoming MMS]
DETECT[MIME Detection]
DECIDE{Needs<br/>Transcoding?}
TRANS[Transcode]
PASS[Pass-through]
OUT[Outgoing MMS]
IN --> DETECT
DETECT --> DECIDE
DECIDE -->|Yes| TRANS
DECIDE -->|No| PASS
TRANS --> OUT
PASS --> OUT
Carrier Size Limits
Different carriers impose different size limits for MMS:
| Tier | Max Size | Carriers |
|---|---|---|
| Tier 1 | 1 MB | Some Tier-1 carriers |
| Tier 2 | 600 KB | Telnyx, most carriers |
| Tier 3 | 300 KB | Strict carriers, international |
GOMSGGW targets Tier 2 (600 KB) by default for maximum compatibility.
Supported Media Types
Images
| Input Format | Transcoding | Output |
|---|---|---|
| JPEG | Resize/compress if needed | JPEG |
| PNG | Convert + compress | JPEG |
| GIF (static) | Convert | JPEG |
| GIF (animated) | Pass-through or skip | GIF |
| WebP | Convert | JPEG |
| HEIC | Convert | JPEG |
Processing Steps:
- Decode the image
- Resize if dimensions exceed target
- Re-encode as JPEG with quality adjustment
- Iterate quality until size target met
Video
| Input Format | Transcoding | Output |
|---|---|---|
| MP4 | Transcode if needed | MP4 (H.264) |
| MOV | Convert | MP4 |
| AVI | Convert | MP4 |
| WebM | Convert | MP4 |
| 3GP | Optimize | 3GP |
Processing Steps:
- Analyze input video properties
- Transcode using FFmpeg:
- Video: H.264 baseline profile
- Audio: AAC mono/stereo
- Target bitrate for size compliance
- Fallback to 3GP format for maximum compatibility
Audio
| Input Format | Transcoding | Output |
|---|---|---|
| MP3 | Pass-through or compress | MP3 |
| WAV | Convert | MP3 |
| M4A | Convert | MP3 |
| OGG | Convert | MP3 |
| AMR | Pass-through | AMR |
Transcoding Strategies
Adaptive Quality
The transcoder uses an iterative approach for images:
// Pseudocode
quality := 85
for quality >= 50 {
encoded := encodeJPEG(image, quality)
if len(encoded) <= targetSize {
return encoded
}
quality -= 5
}
return errorTooLarge()
Dimension Limits
Maximum dimensions are enforced to reduce file sizes:
| Media Type | Max Width | Max Height |
|---|---|---|
| Images | 1920 px | 1920 px |
| Videos | 1280 px | 720 px |
FFmpeg Integration
Video and audio transcoding uses FFmpeg with optimized profiles:
# Video transcoding example
ffmpeg -i input.mov \
-c:v libx264 -profile:v baseline -level 3.0 \
-c:a aac -ac 2 -b:a 128k \
-movflags +faststart \
-maxrate 500k -bufsize 1M \
output.mp4
Web Client Message Splitting
Web clients can control whether long messages are split into multiple SMS segments via ClientSettings:
{
"disable_message_splitting": true
}
What disable_message_splitting Does
By default, messages longer than 160 characters (GSM-7) or 70 characters (UCS-2) are split into multiple SMS segments with UDH headers so the receiving handset can reassemble them.
When disable_message_splitting: true:
- The full message body is delivered to the destination in a single payload (web→web only)
- The original segment count is preserved in the message record
- This only applies to web-to-web delivery; if the destination is a legacy (SMPP/MM4) client or a carrier, splitting still happens to comply with protocol limits
Note
This setting affects message segmentation, not media transcoding. MMS media is always processed through the transcoding pipeline described above.
When to Disable Splitting
Useful when the receiving web application prefers to handle a single long string rather than reassemble UDH-segmented parts. Most modern backends already reassemble automatically, so leaving splitting enabled (the default) is usually correct.
Error Handling
Transcoding Failures
When transcoding fails, the system:
- Logs the error with details
- Attempts fallback strategies:
- Try lower quality settings
- Try alternative format
- Skip the problematic file
- Sends error notification to sender (if configured)
Size Limit Exceeded
If a file cannot be reduced to the target size:
{
"error": "media_too_large",
"message": "Image could not be reduced to carrier limits",
"original_size": 5242880,
"target_size": 614400,
"filename": "large_photo.png"
}
Unsupported Format
For unrecognized media types:
{
"error": "unsupported_media_type",
"message": "Media type not supported for MMS",
"content_type": "application/octet-stream",
"filename": "document.exe"
}
Performance Considerations
CPU Usage
Video transcoding is CPU-intensive. Consider:
- Limiting concurrent transcode operations
- Using a dedicated transcoding worker pool
- Horizontal scaling for high-volume deployments
Temporary Storage
The transcoder uses temporary files during processing:
- Located in system temp directory
- Automatically cleaned up after processing
- Consider tmpfs for improved performance
Caching
Transcoded media can be cached by content hash:
- Avoids re-processing identical files
- Useful for repeated sends of same media
- Configure cache size based on available storage
Monitoring
Metrics
The transcoding system exposes Prometheus metrics:
| Metric | Type | Description |
|---|---|---|
mms_transcode_total | Counter | Total transcode operations |
mms_transcode_duration_seconds | Histogram | Transcode operation duration |
mms_transcode_errors_total | Counter | Failed transcode operations |
mms_transcode_bytes_saved | Counter | Bytes reduced by transcoding |
Logging
Transcoding operations are logged at INFO level:
{
"level": "info",
"component": "transcoder",
"event": "transcode_complete",
"input_type": "image/png",
"output_type": "image/jpeg",
"input_size": 2048576,
"output_size": 512000,
"quality": 75,
"duration_ms": 245
}
Configuration
Environment Variables
| Variable | Default | Description |
|---|---|---|
MMS_MAX_SIZE | 614400 | Target size in bytes (600KB) |
MMS_IMAGE_QUALITY | 85 | Initial JPEG quality |
MMS_VIDEO_BITRATE | 500k | Target video bitrate |
FFMPEG_PATH | /usr/bin/ffmpeg | FFmpeg binary location |
TRANSCODER_WORKERS | 4 | Concurrent transcode workers |
Best Practices
For Legacy Clients
- Always leave transcoding enabled
- Trust the gateway to optimize for delivery
For Web Clients
- Only disable transcoding if you manage media optimization
- Consider the destination when disabling
- Monitor for delivery failures
For High Volume
- Scale horizontally for transcoding capacity
- Consider dedicated transcoding workers
- Implement media caching