{"id":15030619,"url":"https://github.com/videoflint/cabbage","last_synced_at":"2025-05-15T16:07:18.914Z","repository":{"id":39120955,"uuid":"143089251","full_name":"VideoFlint/Cabbage","owner":"VideoFlint","description":"A video composition framework build on top of AVFoundation. It's simple to use and easy to extend.","archived":false,"fork":false,"pushed_at":"2023-11-08T00:02:29.000Z","size":28707,"stargazers_count":1564,"open_issues_count":46,"forks_count":229,"subscribers_count":35,"default_branch":"master","last_synced_at":"2025-05-13T18:44:30.294Z","etag":null,"topics":["audio","avfoundation","video","video-processing","videoediting"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/VideoFlint.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2018-08-01T01:42:02.000Z","updated_at":"2025-05-13T15:08:28.000Z","dependencies_parsed_at":"2024-01-29T18:06:55.965Z","dependency_job_id":null,"html_url":"https://github.com/VideoFlint/Cabbage","commit_stats":{"total_commits":89,"total_committers":11,"mean_commits":8.090909090909092,"dds":0.1910112359550562,"last_synced_commit":"41c78700c32b3814eaa242a3b4fe9323e14d63fc"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VideoFlint%2FCabbage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VideoFlint%2FCabbage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VideoFlint%2FCabbage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VideoFlint%2FCabbage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VideoFlint","download_url":"https://codeload.github.com/VideoFlint/Cabbage/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254374475,"owners_count":22060611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["audio","avfoundation","video","video-processing","videoediting"],"created_at":"2024-09-24T20:13:52.879Z","updated_at":"2025-05-15T16:07:16.660Z","avatar_url":"https://github.com/VideoFlint.png","language":"Swift","readme":"![](https://ws1.sinaimg.cn/large/6ca4705bgy1ftvakl767wj215o07st9r.jpg)\n\n[中文说明](https://github.com/VideoFlint/Cabbage/wiki/中文说明) [中文使用文档](https://github.com/VideoFlint/Cabbage/wiki/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3)\n\nA high-level video composition framework build on top of AVFoundation. It's simple to use and easy to extend. Use it and make life easier if you are implementing video composition feature.\n\nThis project has a Timeline concept. Any resource can put into Timeline. A resource can be Image, Video, Audio, Gif and so on.\n\n## Features\n\n- Build result content objcet with only few step. \n\n1. Create resource  \n2. Set configuration \n3. Put them into Timeline\n4. Use Timeline to generate AVPlayerItem/AVAssetImageGenerator/AVExportSession\n\n- Resouce: Support video, audio, and image. Resource is extendable, you can create your customized resource type. e.g gif image resource\n- Video configuration support: transform, opacity and so on. The configuration is extendable.\n- Audio configuration support: change volume or process with audio raw data in real time. The configuration is extendable.\n- Transition: Clips may transition with previous and next clip\n\n## Usage\n\nBelow is the simplest example. Create a resource from AVAsset, set the video frame's scale mode to aspect fill, then insert trackItem to timeline, after all use CompositionGenerator to build AVAssetExportSession/AVAssetImageGenerator/AVPlayerItem.\n\n```Swift\n\n// 1. Create a resource\nlet asset: AVAsset = ...     \nlet resource = AVAssetTrackResource(asset: asset)\n\n// 2. Create a TrackItem instance, TrackItem can configure video\u0026audio configuration\nlet trackItem = TrackItem(resource: resource)\n// Set the video scale mode on canvas\ntrackItem.configuration.videoConfiguration.baseContentMode = .aspectFill\n\n// 3. Add TrackItem to timeline\nlet timeline = Timeline()\ntimeline.videoChannel = [trackItem]\ntimeline.audioChannel = [trackItem]\n\n// 4. Use CompositionGenerator to create AVAssetExportSession/AVAssetImageGenerator/AVPlayerItem\nlet compositionGenerator = CompositionGenerator(timeline: timeline)\n// Set the video canvas's size\ncompositionGenerator.renderSize = CGSize(width: 1920, height: 1080)\nlet exportSession = compositionGenerator.buildExportSession(presetName: AVAssetExportPresetMediumQuality)\nlet playerItem = compositionGenerator.buildPlayerItem()\nlet imageGenerator = compositionGenerator.buildImageGenerator()\n\n```\n\n### Basic Concept\n\n**Timeline**\n\nUse to construct resource, the developer is responsible for putting resources at the right time range.\n\n**CompositionGenerator**\n\nUse CompositionGenerator to create AVAssetExportSession/AVAssetImageGenerator/AVPlayerItem\n\nCompositionGenerator use Timeline instance translate to AVFoundation API.\n\n**Resource**\n\nResource provider Image or/and audio data. It also provide time infomation about the data.\n\nCurrently support\n\n - Image type: \n    - `ImageResource`: Provide a CIImage as video frame\n    - `PHAssetImageResource`: Provide a PHAsset, load CIImage as video frame\n    - `AVAssetReaderImageResource`: Provide AVAsset, reader samplebuffer as video frame using AVAssetReader\n    - `AVAssetReverseImageResource`: Provide AVAsset, reader samplebuffer as video frame using AVAssetReader, but reverse the order\n - Video\u0026Audio type: \n    - `AVAssetTrackResource`: Provide AVAsset, use AVAssetTrack as video frame and audio frame.\n    - `PHAssetTrackResource`: Provide PHAsset, load AVAsset from it.\n\n**TrackItem**\n\nA TrackItem contains Resource, VideoConfiguration and AudioConfiguration.\n\nCurrently support\n\n- Video Configuration\n    - baseContentMode, video frame's scale mode base on canvas size\n    - transform\n    - opacity\n    - configurations, custom filter can be added here.\n- Audio Configuration\n    - volume\n    - nodes, apply custom audio process operation, e.g VolumeAudioConfiguration\n- videoTransition, audioTransition\n\n\n## Advance usage\n\n### Custom Resource\n\nYou can provide custom resource type by subclass `Resource`, and implement `func tracks(for type: AVMediaType) -\u003e [AVAssetTrack]`.\n\nBy subclass `ImageResource`, you can use CIImage as video frame.\n\n### Custom Image Filter\n\nImage filter need Implement `VideoConfigurationProtocol` protocol, then it can be added to `TrackItem.configuration.videoConfiguration.configurations`\n\n`KeyframeVideoConfiguration` is a concrete class.\n\n### Custom Audio Mixer\n\nAudio Mixer need implement `AudioConfigurationProtocol` protocol, then it can be added to `TrackItem.configuration.audioConfiguration.nodes`\n\n`VolumeAudioConfiguration` is a concrete class.\n\n## Why I create this project\n\nAVFoundation aready provide powerful composition API for video and audio, but these API are far away from easy to use.\n\n**1.AVComposition**\n\nWe need to know how and when to connect different tracks. Say we save the time range info for a track, finnaly we will realize the time range info is very easy to broken, consider below scenarios\n\n- Change previous track's time range info\n- Change speed\n- Add new track\n- Add/remove transition\n\nThese operations will affect the timeline and all tracks' time range info need to be updated.\n\nBad thing is that AVComposition only supports video track and audio track. If we want to combine photo and video, it's very difficult to implement.\n\n**2.AVVideoCompostion**\n\nUse `AVVideoCompositionInstruction` to construct timeline, use `AVVideoCompositionLayerInstruction` to configure track's transform. If we want to operate raw video frame data, need implement `AVVideoCompositing` protocol.\n\nAfter I write the code, I realized there are many codes unrelated to business logic, they should be encapsulated.\n\n**3.Difffcult to extend features**\n\nAVFoundation only supports a few basic composition features. As far as I know, it only can change video frame transform and audio volume. If a developer wants to implement other features, e.g apply a filter to a video frame, then need to rewrite AVVideoCompostion's `AVVideoCompositing` protocol. The workload suddenly become very large.\n\nLife is hard why should I write hard code too? So I create Cabbage, easy to understand API, flexible feature scalability.\n\n## Installation\n\n**Cocoapods**\n\n```\nplatform :ios, '9.0'\nuse_frameworks!\n\ntarget 'MyApp' do\n  # your other pod\n  # ...\n  pod 'VFCabbage'\nend\n```\n\n**Manually**\n\nIt is not recommended to install the framework manually, but if you have to do it manually.\nYou can \n\n- simplely drag `Cabbage/Sources` folder to you project.\n- Or add Cabbage as a submodule.\n\n```\n$ git submodule add https://github.com/VideoFlint/Cabbage.git\n```\n\n## Requirements\n\n- iOS 9.0+\n- Swift 4.x\n\n## Projects using Cabbage\n\n- [VideoCat](https://github.com/vitoziv/VideoCat): A demo project demonstrates how to use Cabbage.\n\n## LICENSE\n\nUnder MIT\n\n## Special Thanks\n\n- Icon designed by [熊猫先生](https://dribbble.com/viennaong)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvideoflint%2Fcabbage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvideoflint%2Fcabbage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvideoflint%2Fcabbage/lists"}