fix video compression issues #25

This commit is contained in:
otsmr 2025-04-29 14:48:48 +02:00
parent 0f7b1755ba
commit 06715e8ac9
5 changed files with 74 additions and 52 deletions

View file

@ -181,7 +181,7 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
await writeMediaFile(media.messageId, "mp4", splited[1]);
}
await writeMediaFile(media.messageId, "image", imageBytes);
await writeMediaFile(media.messageId, "png", imageBytes);
} catch (e) {
Logger("media_received.dart").info("Decryption error: $e");
await twonlyDatabase.messagesDao.updateMessageByMessageId(
@ -207,7 +207,7 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
}
Future<Uint8List?> getImageBytes(int mediaId) async {
return await readMediaFile(mediaId, "image");
return await readMediaFile(mediaId, "png");
}
Future<File?> getVideoPath(int mediaId) async {

View file

@ -17,6 +17,7 @@ import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/api/api_utils.dart';
import 'package:twonly/src/services/notification_service.dart';
import 'package:video_compress/video_compress.dart';
Future sendMediaFile(
List<int> userIds,
@ -43,9 +44,9 @@ Future sendMediaFile(
if (mediaUploadId != null) {
if (videoFilePath != null) {
String basePath = await getMediaFilePath(mediaUploadId, "send");
await File(videoFilePath.path).rename("$basePath.video");
await File(videoFilePath.path).rename("$basePath.mp4");
}
await writeMediaFile(mediaUploadId, "image", imageBytes);
await writeMediaFile(mediaUploadId, "png", imageBytes);
await handleSingleMediaFile(mediaUploadId);
}
}
@ -165,7 +166,7 @@ Future handleAddToMessageDb(MediaUpload media) async {
}
Future handleCompressionState(MediaUpload media) async {
Uint8List imageBytes = await readMediaFile(media, "image");
Uint8List imageBytes = await readMediaFile(media, "png");
try {
Uint8List imageBytesCompressed =
@ -184,54 +185,56 @@ Future handleCompressionState(MediaUpload media) async {
);
}
await writeMediaFile(
media.mediaUploadId, "image.compressed", imageBytesCompressed);
media.mediaUploadId, "compressed.png", imageBytesCompressed);
} catch (e) {
Logger("media_send.dart").shout("$e");
// as a fall back use the original image
await writeMediaFile(media.mediaUploadId, "image.compressed", imageBytes);
await writeMediaFile(media.mediaUploadId, "compressed.png", imageBytes);
}
if (media.metadata.isVideo) {
String basePath = await getMediaFilePath(media.mediaUploadId, "send");
File videoOriginalFile = File("$basePath.video");
File videoCompressedFile = File("$basePath.video.compressed");
File videoOriginalFile = File("$basePath.mp4");
File videoCompressedFile = File("$basePath.compressed.mp4");
// MediaInfo? mediaInfo;
MediaInfo? mediaInfo;
try {
// mediaInfo = await VideoCompress.compressVideo(
// videoOriginalFile.path,
// quality: VideoQuality.Res1280x720Quality,
// deleteOrigin: false,
// includeAudio: media.metadata.videoWithAudio,
// );
mediaInfo = await VideoCompress.compressVideo(
videoOriginalFile.path,
quality: VideoQuality.Res1280x720Quality,
deleteOrigin: false,
includeAudio:
true, // https://github.com/jonataslaw/VideoCompress/issues/184
);
// if (mediaInfo!.filesize! >= 20 * 1000 * 1000) {
// // if the media file is over 20MB compress it with low quality
// mediaInfo = await VideoCompress.compressVideo(
// videoOriginalFile.path,
// quality: VideoQuality.Res960x540Quality,
// deleteOrigin: false,
// includeAudio: media.metadata.videoWithAudio,
// );
// }
if (mediaInfo!.filesize! >= 20 * 1000 * 1000) {
// if the media file is over 20MB compress it with low quality
mediaInfo = await VideoCompress.compressVideo(
videoOriginalFile.path,
quality: VideoQuality.Res960x540Quality,
deleteOrigin: false,
includeAudio: media.metadata.videoWithAudio,
);
}
} catch (e) {
Logger("media_send.dart").shout("Video compression: $e");
}
// if (mediaInfo == null) {
// as a fall back use the non compressed version
await videoOriginalFile.copy(videoCompressedFile.path);
await videoOriginalFile.delete();
// } else {
// Logger("media_send.dart").shout("Error compressing video.");
// mediaInfo!.file!.rename(videoCompressedFile.path);
// }
if (mediaInfo == null) {
Logger("media_send.dart").shout("Error compressing video.");
// as a fall back use the non compressed version
await videoOriginalFile.copy(videoCompressedFile.path);
await videoOriginalFile.delete();
} else {
await mediaInfo.file!.copy(videoCompressedFile.path);
await mediaInfo.file!.delete();
}
}
// delete non compressed media files
await deleteMediaFile(media, "image");
await deleteMediaFile(media, "video");
await deleteMediaFile(media, "png");
await deleteMediaFile(media, "mp4");
await twonlyDatabase.mediaUploadsDao.updateMediaUpload(
media.mediaUploadId,
@ -246,10 +249,10 @@ Future handleCompressionState(MediaUpload media) async {
Future handleEncryptionState(MediaUpload media) async {
var state = MediaEncryptionData();
Uint8List dataToEncrypt = await readMediaFile(media, "image.compressed");
Uint8List dataToEncrypt = await readMediaFile(media, "compressed.png");
if (media.metadata.isVideo) {
Uint8List compressedVideo = await readMediaFile(media, "video.compressed");
Uint8List compressedVideo = await readMediaFile(media, "compressed.mp4");
dataToEncrypt = combineUint8Lists(dataToEncrypt, compressedVideo);
}

View file

@ -41,6 +41,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
bool useHighQuality = false;
bool isVideoRecording = false;
bool hasAudioPermission = true;
bool videoWithAudio = true;
DateTime? videoRecordingStarted;
Timer? videoRecordingTimer;
DateTime currentTime = DateTime.now();
@ -105,7 +106,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
controller = CameraController(
gCameras[sCameraId],
ResolutionPreset.high,
enableAudio: await Permission.microphone.isGranted,
enableAudio: await Permission.microphone.isGranted && videoWithAudio,
);
controller?.initialize().then((_) async {
if (!mounted) {
@ -508,7 +509,23 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
tooltipText:
"Allow microphone access for video recording.",
onPressed: requestMicrophonePermission,
)
),
if (hasAudioPermission)
ActionButton(
(videoWithAudio)
? Icons.volume_up_rounded
: Icons.volume_off_rounded,
tooltipText: "Record video with audio.",
color: (videoWithAudio)
? Colors.white
: Colors.white.withAlpha(160),
onPressed: () async {
setState(() {
videoWithAudio = !videoWithAudio;
});
selectCamera(cameraId);
},
),
],
),
),

View file

@ -196,18 +196,19 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
},
),
),
if (widget.videoFilePath != null) const SizedBox(height: 8),
if (widget.videoFilePath != null)
ActionButton(
(videoWithAudio) ? Icons.volume_up_rounded : Icons.volume_off_rounded,
tooltipText: context.lang.protectAsARealTwonly,
color: Colors.white,
onPressed: () async {
setState(() {
videoWithAudio = !videoWithAudio;
});
},
),
// https://github.com/jonataslaw/VideoCompress/issues/184
// if (widget.videoFilePath != null) const SizedBox(height: 8),
// if (widget.videoFilePath != null)
// ActionButton(
// (videoWithAudio) ? Icons.volume_up_rounded : Icons.volume_off_rounded,
// tooltipText: context.lang.protectAsARealTwonly,
// color: Colors.white,
// onPressed: () async {
// setState(() {
// videoWithAudio = !videoWithAudio;
// });
// },
// ),
const SizedBox(height: 8),
ActionButton(
FontAwesomeIcons.shieldHeart,
@ -287,6 +288,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
isRealTwonly: _isRealTwonly,
maxShowTime: maxShowTime,
preselectedUser: widget.sendTo,
videoFilePath: widget.videoFilePath,
),
),
);

View file

@ -23,7 +23,7 @@ class ShareImageView extends StatefulWidget {
required this.isRealTwonly,
required this.maxShowTime,
this.preselectedUser,
this.videoFilePath,
required this.videoFilePath,
this.enableVideoAudio});
final Future<Uint8List?> imageBytesFuture;
final bool isRealTwonly;