Skip to content

Commit e0029df

Browse files
committed
Improve HLS API with structured HlsVariant and refactor sample test
1 parent 63416ef commit e0029df

9 files changed

Lines changed: 3230 additions & 143 deletions

File tree

.agents/skills/gh-cli/SKILL.md

Lines changed: 2187 additions & 0 deletions
Large diffs are not rendered by default.

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"java.compile.nullAnalysis.mode": "automatic"
3+
}

AGENTS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# AI Agent Disclosure
2+
3+
Some issue triage, responses, and maintenance tasks on this repository may be
4+
performed by an AI agent (GitHub Copilot) acting on behalf of @bramp.
5+
6+
When this happens, the response will clearly state that it was written by an AI
7+
agent. All AI-generated responses are reviewed or approved by @bramp before or
8+
shortly after posting.
9+
10+
If you have concerns about an AI-generated response, please tag @bramp directly.

ISSUE_RESPONSES.md

Lines changed: 730 additions & 0 deletions
Large diffs are not rendered by default.

TODO.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# PR Review TODO List
2+
3+
This list tracks the next steps for the 6 open pull requests in `bramp/ffmpeg-cli-wrapper`.
4+
5+
## 🟢 Completed
6+
- [x] **PR #366**: Add color_space related options to FFProbeStream
7+
- [x] **PR #362**: Add -map option
8+
9+
## 🟡 Rebase Required (CI Failures)
10+
- [x] **PR #361**: fix/passlog-files-not-deleted
11+
- [ ] **PR #377**: Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.0 to 3.2.8
12+
- **Action:** Rebase via Dependabot.
13+
- **Details:** Standard dependency update. Current failure is due to the same transient CI issue as #361.
14+
15+
## 🔴 Needs Update or Redesign
16+
- [x] **PR #294**: Add Sample Test to convert media file in hls format
17+
- [ ] **PR #178**: Added support for input devices/streams and tests
18+
- **Action:** Architectural redesign.
19+
- **Files:** `FFmpegInputBuilder.java` (new), `FFmpegBuilder.java`.
20+
- **Issue:** 7 years old. Duplicates `build()` logic from output builders and hardcodes specific flags like `-video_device_number`.
21+
- **Redesign Goal:** Create a shared base or interface for "Builders that can generate `-i` options" to support devices (v4l2, dshow, x11grab) without duplicating the entire option-building logic.
22+
23+
---
24+
*Generated by Gemini CLI on 2026-04-03*

skills-lock.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"version": 1,
3+
"skills": {
4+
"gh-cli": {
5+
"source": "github/awesome-copilot",
6+
"sourceType": "github",
7+
"computedHash": "cbe644b0c6760ae2a1eaafa39133920d889331327065d92a131675a665273e56"
8+
}
9+
}
10+
}

src/main/java/net/bramp/ffmpeg/builder/FFmpegHlsOutputBuilder.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import com.google.common.base.Strings;
88
import com.google.common.collect.ImmutableList;
9+
import java.util.ArrayList;
10+
import java.util.List;
911
import java.util.concurrent.TimeUnit;
1012
import javax.annotation.CheckReturnValue;
1113

@@ -16,6 +18,11 @@ public class FFmpegHlsOutputBuilder extends AbstractFFmpegOutputBuilder<FFmpegHl
1618
public Long hls_init_time;
1719
public Integer hls_list_size;
1820
public String hls_base_url;
21+
public String hls_playlist_type;
22+
public String master_pl_name;
23+
public String var_stream_map;
24+
25+
private final List<HlsVariant> variants = new ArrayList<>();
1926

2027
protected FFmpegHlsOutputBuilder(FFmpegBuilder parent, String filename) {
2128
super(parent, filename);
@@ -107,6 +114,52 @@ public FFmpegHlsOutputBuilder setHlsBaseUrl(String baseurl) {
107114
return this;
108115
}
109116

117+
/**
118+
* Set the playlist type.
119+
*
120+
* @param type The playlist type (e.g. "event", "vod")
121+
* @return {@link FFmpegHlsOutputBuilder}
122+
*/
123+
public FFmpegHlsOutputBuilder setHlsPlaylistType(String type) {
124+
this.hls_playlist_type = checkNotEmpty(type, "type must not be empty");
125+
return this;
126+
}
127+
128+
/**
129+
* Set the master playlist name.
130+
*
131+
* @param name The master playlist name
132+
* @return {@link FFmpegHlsOutputBuilder}
133+
*/
134+
public FFmpegHlsOutputBuilder setMasterPlName(String name) {
135+
this.master_pl_name = checkNotEmpty(name, "name must not be empty");
136+
return this;
137+
}
138+
139+
/**
140+
* Set the variant stream map string manually.
141+
*
142+
* <p>Prefer using {@link #addVariant(HlsVariant)} for a cleaner API.
143+
*
144+
* @param map The variant stream map (e.g. "v:0,a:0 v:1,a:1")
145+
* @return {@link FFmpegHlsOutputBuilder}
146+
*/
147+
public FFmpegHlsOutputBuilder setVarStreamMap(String map) {
148+
this.var_stream_map = checkNotEmpty(map, "map must not be empty");
149+
return this;
150+
}
151+
152+
/**
153+
* Adds an HLS variant to this output.
154+
*
155+
* @param variant The variant configuration.
156+
* @return {@link FFmpegHlsOutputBuilder}
157+
*/
158+
public FFmpegHlsOutputBuilder addVariant(HlsVariant variant) {
159+
this.variants.add(checkNotNull(variant));
160+
return this;
161+
}
162+
110163
@Override
111164
protected void addFormatArgs(ImmutableList.Builder<String> args) {
112165
super.addFormatArgs(args);
@@ -129,6 +182,27 @@ protected void addFormatArgs(ImmutableList.Builder<String> args) {
129182
if (!Strings.isNullOrEmpty(hls_base_url)) {
130183
args.add("-hls_base_url", hls_base_url);
131184
}
185+
186+
if (!Strings.isNullOrEmpty(hls_playlist_type)) {
187+
args.add("-hls_playlist_type", hls_playlist_type);
188+
}
189+
190+
if (!Strings.isNullOrEmpty(master_pl_name)) {
191+
args.add("-master_pl_name", master_pl_name);
192+
}
193+
194+
if (!Strings.isNullOrEmpty(var_stream_map)) {
195+
args.add("-var_stream_map", var_stream_map);
196+
} else if (!variants.isEmpty()) {
197+
StringBuilder sb = new StringBuilder();
198+
for (int i = 0; i < variants.size(); i++) {
199+
if (i > 0) {
200+
sb.append(" ");
201+
}
202+
sb.append(variants.get(i).toString());
203+
}
204+
args.add("-var_stream_map", sb.toString());
205+
}
132206
}
133207

134208
@CheckReturnValue
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package net.bramp.ffmpeg.builder;
2+
3+
import static com.google.common.base.Preconditions.checkArgument;
4+
import static com.google.common.base.Preconditions.checkNotNull;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
/**
10+
* Represents an HLS variant stream mapping.
11+
*
12+
* <p>Used with {@code -var_stream_map} to group audio, video, and subtitle streams.
13+
*/
14+
public class HlsVariant {
15+
16+
private final List<String> streams = new ArrayList<>();
17+
private String name;
18+
19+
public HlsVariant() {}
20+
21+
/**
22+
* Adds a video stream to this variant.
23+
*
24+
* @param index The zero-based index of the video stream in the output.
25+
* @return this
26+
*/
27+
public HlsVariant addVideo(int index) {
28+
checkArgument(index >= 0, "index must be >= 0");
29+
streams.add("v:" + index);
30+
return this;
31+
}
32+
33+
/**
34+
* Adds an audio stream to this variant.
35+
*
36+
* @param index The zero-based index of the audio stream in the output.
37+
* @return this
38+
*/
39+
public HlsVariant addAudio(int index) {
40+
checkArgument(index >= 0, "index must be >= 0");
41+
streams.add("a:" + index);
42+
return this;
43+
}
44+
45+
/**
46+
* Adds a subtitle stream to this variant.
47+
*
48+
* @param index The zero-based index of the subtitle stream in the output.
49+
* @return this
50+
*/
51+
public HlsVariant addSubtitle(int index) {
52+
checkArgument(index >= 0, "index must be >= 0");
53+
streams.add("s:" + index);
54+
return this;
55+
}
56+
57+
/**
58+
* Sets the name for this variant.
59+
*
60+
* @param name The variant name (e.g., "1080p").
61+
* @return this
62+
*/
63+
public HlsVariant setName(String name) {
64+
this.name = checkNotNull(name);
65+
return this;
66+
}
67+
68+
@Override
69+
public String toString() {
70+
if (streams.isEmpty()) {
71+
return "";
72+
}
73+
StringBuilder sb = new StringBuilder();
74+
for (int i = 0; i < streams.size(); i++) {
75+
if (i > 0) {
76+
sb.append(",");
77+
}
78+
sb.append(streams.get(i));
79+
}
80+
if (name != null && !name.isEmpty()) {
81+
sb.append(",name:").append(name);
82+
}
83+
return sb.toString();
84+
}
85+
}

0 commit comments

Comments
 (0)