{"id":39430288,"url":"https://github.com/alec-c4/ffmpeg_core","last_synced_at":"2026-01-27T15:07:33.346Z","repository":{"id":332623139,"uuid":"1134310691","full_name":"alec-c4/ffmpeg_core","owner":"alec-c4","description":"Modern Ruby wrapper for FFmpeg with clean API and proper error handling.","archived":false,"fork":false,"pushed_at":"2026-01-16T12:21:25.000Z","size":71,"stargazers_count":9,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-21T17:38:51.100Z","etag":null,"topics":["ffmpeg","ffmpeg-wrapper","ruby","ruby-on-rails","video","video-processing"],"latest_commit_sha":null,"homepage":"https://alec-c4.com","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alec-c4.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-14T14:47:26.000Z","updated_at":"2026-01-17T11:49:51.000Z","dependencies_parsed_at":"2026-01-19T05:00:37.769Z","dependency_job_id":null,"html_url":"https://github.com/alec-c4/ffmpeg_core","commit_stats":null,"previous_names":["alec-c4/ffmpeg_core"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/alec-c4/ffmpeg_core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alec-c4%2Fffmpeg_core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alec-c4%2Fffmpeg_core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alec-c4%2Fffmpeg_core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alec-c4%2Fffmpeg_core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alec-c4","download_url":"https://codeload.github.com/alec-c4/ffmpeg_core/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alec-c4%2Fffmpeg_core/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28815386,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T12:25:15.069Z","status":"ssl_error","status_checked_at":"2026-01-27T12:25:05.297Z","response_time":168,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffmpeg","ffmpeg-wrapper","ruby","ruby-on-rails","video","video-processing"],"created_at":"2026-01-18T04:02:54.387Z","updated_at":"2026-01-27T15:07:33.329Z","avatar_url":"https://github.com/alec-c4.png","language":"Ruby","readme":"# FFmpegCore\n\nModern Ruby wrapper for FFmpeg with clean API and proper error handling.\n\n[![Gem Version](https://badge.fury.io/rb/ffmpeg_core.svg)](https://badge.fury.io/rb/ffmpeg_core)\n[![Build Status](https://github.com/alec-c4/ffmpeg_core/actions/workflows/main.yml/badge.svg)](https://github.com/alec-c4/ffmpeg_core/actions)\n\n## Features\n\n- Modern Ruby 3+ conventions\n- Zero runtime dependencies\n- **Real-time progress reporting**\n- **Support for video/audio filters and quality presets**\n- **Remote input support (HTTP/HTTPS/RTMP/RTSP)**\n- Proper error handling with detailed context\n- Thread-safe configuration\n- Simple, intuitive API\n\n## Requirements\n\n- Ruby 3.2+\n- FFmpeg installed (`brew install ffmpeg` on macOS)\n\n## Installation\n\nAdd to your Gemfile:\n\n```ruby\ngem \"ffmpeg_core\"\n```\n\nThen run:\n\n```bash\nbundle install\n```\n\n## Usage\n\n### Basic Usage\n\n```ruby\nrequire \"ffmpeg_core\"\n\n# Load a video file or remote URL\nmovie = FFmpegCore::Movie.new(\"input.mp4\")\n# movie = FFmpegCore::Movie.new(\"http://example.com/video.mp4\")\n\n# Get metadata\nmovie.duration      # =\u003e 120.5 (seconds)\nmovie.resolution    # =\u003e \"1920x1080\" (automatically swapped if rotated)\nmovie.width         # =\u003e 1920\nmovie.height        # =\u003e 1080\nmovie.video_codec   # =\u003e \"h264\"\nmovie.audio_codec   # =\u003e \"aac\"\nmovie.frame_rate    # =\u003e 29.97\nmovie.bitrate       # =\u003e 5000 (kb/s)\nmovie.valid?        # =\u003e true\n\n# Access detailed metadata via probe\nmovie.probe.rotation      # =\u003e 90 (degrees)\nmovie.probe.aspect_ratio  # =\u003e \"16:9\"\nmovie.probe.video_profile # =\u003e \"High\"\nmovie.probe.video_level   # =\u003e 41\n```\n\n### Transcoding\n\n```ruby\nmovie = FFmpegCore::Movie.new(\"input.mp4\")\n\n# Basic transcoding with progress\nmovie.transcode(\"output.mp4\", video_codec: \"libx264\") do |progress|\n  puts \"Progress: #{(progress * 100).round(2)}%\"\nend\n\n# Advanced options (Filters \u0026 Quality)\nmovie.transcode(\"output.mp4\", {\n  video_codec: \"libx264\",\n  audio_codec: \"aac\",\n  video_bitrate: \"1000k\",\n  audio_bitrate: \"128k\",\n  resolution: \"1280x720\",\n  crop: { width: 500, height: 500, x: 10, y: 10 }, # Crop video\n  video_filter: \"scale=1280:-1,transpose=1\", # Resize and rotate\n  audio_filter: \"volume=0.5\",                # Reduce volume\n  preset: \"slow\",      # ffmpeg preset (ultrafast, fast, medium, slow, etc.)\n  crf: 23,             # Constant Rate Factor (0-51)\n  custom: %w[-map 0:v -map 0:a] # Custom FFmpeg flags\n})\n```\n\n### Using Filters\n\nFFmpegCore supports raw FFmpeg filter strings for both video (`video_filter` or `-vf`) and audio (`audio_filter` or `-af`).\n\n**Common Video Filters:**\n\n```ruby\nmovie.transcode(\"output.mp4\", {\n  # Scale to width 1280, keep aspect ratio\n  video_filter: \"scale=1280:-1\",\n\n  # Crop 100x100 starting at position (10,10)\n  video_filter: \"crop=100:100:10:10\",\n\n  # Rotate 90 degrees clockwise\n  video_filter: \"transpose=1\",\n\n  # Chain multiple filters (Scale then Rotate)\n  video_filter: \"scale=1280:-1,transpose=1\"\n})\n```\n\n**Common Audio Filters:**\n\n```ruby\nmovie.transcode(\"output.mp4\", {\n  # Increase volume by 50%\n  audio_filter: \"volume=1.5\",\n\n  # Fade in first 5 seconds\n  audio_filter: \"afade=t=in:ss=0:d=5\"\n})\n```\n\n### Screenshots\n\n```ruby\nmovie = FFmpegCore::Movie.new(\"input.mp4\")\n\n# Extract screenshot at specific time\nmovie.screenshot(\"thumbnail.jpg\", seek_time: 5)\n\n# With resolution and quality\nmovie.screenshot(\"thumbnail.jpg\", {\n  seek_time: 10,\n  resolution: \"640x360\",\n  quality: 2  # 2-31, lower is better\n})\n```\n\n### Configuration\n\n```ruby\nFFmpegCore.configure do |config|\n  config.ffmpeg_binary = \"/usr/local/bin/ffmpeg\"\n  config.ffprobe_binary = \"/usr/local/bin/ffprobe\"\n  config.timeout = 60\nend\n```\n\n## Error Handling\n\nFFmpegCore provides specific error classes for different failure scenarios. All execution errors (transcoding, probing, screenshots) inherit from `FFmpegCore::ExecutionError`, which provides access to the command, exit status, and stderr output.\n\n```ruby\nbegin\n  movie = FFmpegCore::Movie.new(\"input.mp4\")\n  movie.transcode(\"output.mp4\", video_codec: \"libx264\")\nrescue FFmpegCore::InvalidInputError =\u003e e\n  # File doesn't exist or is not readable\n  puts \"Input error: #{e.message}\"\nrescue FFmpegCore::ExecutionError =\u003e e\n  # Covers TranscodingError, ProbeError, and ScreenshotError\n  puts \"Execution failed: #{e.message}\"\n  puts \"Command: #{e.command}\"\n  puts \"Exit status: #{e.exit_status}\"\n  puts \"Stderr: #{e.stderr}\"\nrescue FFmpegCore::BinaryNotFoundError =\u003e e\n  # FFmpeg not installed\n  puts \"FFmpeg not found: #{e.message}\"\nend\n```\n\n### Error Classes\n\n| Error                             | Description                            | Parent |\n| --------------------------------- | -------------------------------------- | ------ |\n| `FFmpegCore::Error`               | Base error class                       | StandardError |\n| `FFmpegCore::BinaryNotFoundError` | FFmpeg/FFprobe not found               | Error |\n| `FFmpegCore::InvalidInputError`   | Input file doesn't exist or unreadable | Error |\n| `FFmpegCore::OutputError`         | Output file cannot be written          | Error |\n| `FFmpegCore::ExecutionError`      | Base for command execution errors      | Error |\n| `FFmpegCore::ProbeError`          | Failed to extract metadata             | ExecutionError |\n| `FFmpegCore::TranscodingError`    | FFmpeg transcoding failed              | ExecutionError |\n| `FFmpegCore::ScreenshotError`     | Screenshot extraction failed           | ExecutionError |\n\n## Development\n\n```bash\n# Install dependencies\nbundle install\n\n# Run tests\nbundle exec rspec\n\n# Run linter\nbundle exec rubocop\n```\n\n## License\n\nMIT License. See [LICENSE.txt](LICENSE.txt) for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falec-c4%2Fffmpeg_core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falec-c4%2Fffmpeg_core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falec-c4%2Fffmpeg_core/lists"}