combineSegmentsToFile method
Implementation
Future<void> combineSegmentsToFile({
required List<HlsSegmentEntry> segments,
required String segmentDirectoryPath,
required String outputFilePath,
required Map<String, String> customHeaders,
}) async {
if (segments.isEmpty) {
throw const HlsDownloadException(
code: HlsErrorCode.emptyPlaylist,
message: 'No segments to combine',
);
}
final encryptionKeys = await _fetchEncryptionKeys(
segments: segments,
customHeaders: customHeaders,
);
final outputFile = File(outputFilePath);
if (!await outputFile.parent.exists()) {
await outputFile.parent.create(recursive: true);
}
final sink = outputFile.openWrite(mode: FileMode.write);
try {
for (var i = 0; i < segments.length; i++) {
final segment = segments[i];
final segmentPath = p.join(
segmentDirectoryPath,
segmentFileName(i + 1),
);
final segmentFile = File(segmentPath);
if (!await segmentFile.exists()) {
throw HlsDownloadException(
code: HlsErrorCode.segmentMissing,
message: 'Missing downloaded segment: $segmentPath',
);
}
var bytes = await segmentFile.readAsBytes();
final keyUriString = segment.encryptionKeyUri?.toString();
if (keyUriString != null) {
final keyBytes = encryptionKeys[keyUriString];
if (keyBytes == null) {
throw HlsDownloadException(
code: HlsErrorCode.encryptionKeyFetchFailed,
message: 'Missing encryption key bytes for $keyUriString',
);
}
bytes = _decryptSegment(
encryptedBytes: bytes,
keyBytes: keyBytes,
sequenceNumber: segment.sequenceNumber,
ivHex: segment.encryptionIvHex,
);
}
sink.add(bytes);
}
} on HlsDownloadException {
rethrow;
} catch (error, stackTrace) {
throw HlsDownloadException(
code: HlsErrorCode.combineFailed,
message: 'Failed while combining segments',
cause: error,
stackTrace: stackTrace,
);
} finally {
await sink.close();
}
}