improve text and add unsupported audio notification #322

pull/333/head
Mikael Finstad 6 years ago
parent a797d41f89
commit bc1e189d59

@ -86,7 +86,7 @@ Since LosslessCut is based on Chromium and uses the HTML5 video player, not all
The following formats/codecs should generally work: MP4, MOV, WebM, MKV, OGG, WAV, MP3, AAC, H264, Theora, VP8, VP9
For more information about supported formats / codecs, see https://www.chromium.org/audio-video.
Unsupported files can still be converted to a friendly format/codec from the `File` menu. (Try fastest variant first.) A low quality version of the file (without audio) will then be created and opened in the player. The cut/export operation will still be performed on the original file, so it will be lossless. This allows for potentially opening any file that ffmpeg is able to decode.
Unsupported files can still be converted to a supported format/codec from the `File` menu. (Try fastest variant first.) A low quality version of the file (without audio) will then be created and opened in the player. The cut/export operation will still be performed on the original file, so it will be lossless. This allows for potentially opening any file that ffmpeg is able to decode.
## How to use
@ -117,7 +117,7 @@ Note also that the cut is currently not precise around the cutpoints, so video b
- **Cutting times are not accurate and will be "rounded" to the nearest keyframe.** There are wishes to implement a "smart cut" feature that re-encodes only the part before the keyframe, see [#126](https://github.com/mifi/lossless-cut/issues/126)
- Your mileage may vary when it comes to `Keyframe cut` vs `Normal cut`. You may need to try both, depending on the video. See [ffmpeg](https://trac.ffmpeg.org/wiki/Seeking) also has documentation about these two seek/cut modes. `Keyframe cut` means `-ss` *before* `-i` and `Normal cut` means `-ss` *after* `-i`.
- When exporting you may lose some proprietary data tracks (like `tmcd`, `fdsc` and `gpmd` added by GoPro). These can be exported to separate files however
- H265 is not supported natively. There is partial support with very low FPS and no audio preview. Alternatively convert to friendly codec (slow) from the menu, see [#88](https://github.com/mifi/lossless-cut/issues/88)
- H265 is not supported natively. There is partial support with very low FPS and no audio preview. Alternatively convert to supported codec (slow) from the menu, see [#88](https://github.com/mifi/lossless-cut/issues/88)
## Troubleshooting

@ -43,7 +43,7 @@ module.exports = (app, mainWindow, newVersion) => {
},
{ type: 'separator' },
{
label: 'Convert to friendly format',
label: 'Convert to supported format',
click() {
mainWindow.webContents.send('html5ify');
},
@ -123,7 +123,7 @@ module.exports = (app, mainWindow, newVersion) => {
},
},
{
label: 'Batch convert to friendly format',
label: 'Batch convert to supported format',
click() {
mainWindow.webContents.send('batchConvertFriendlyFormat');
},

@ -41,7 +41,7 @@ import {
defaultProcessedCodecTypes, getStreamFps, isCuttingStart, isCuttingEnd,
getDefaultOutFormat, getFormatData, mergeFiles as ffmpegMergeFiles, renderThumbnails as ffmpegRenderThumbnails,
readFrames, renderWaveformPng, html5ifyDummy, cutMultiple, extractStreams, autoMergeSegments, getAllStreams,
findNearestKeyFrameTime, html5ify as ffmpegHtml5ify, isStreamThumbnail,
findNearestKeyFrameTime, html5ify as ffmpegHtml5ify, isStreamThumbnail, isAudioSupported,
} from './ffmpeg';
import { save as edlStoreSave, load as edlStoreLoad } from './edlStore';
import {
@ -843,7 +843,7 @@ const App = memo(() => {
await createDummyVideo(customOutDir, filePath);
} catch (err) {
console.error(err);
errorToast(i18n.t('Failed to playback this file. Try to convert to friendly format from the menu'));
errorToast(i18n.t('Failed to playback this file. Try to convert to supported format from the menu'));
} finally {
setWorking();
}
@ -861,7 +861,7 @@ const App = memo(() => {
if (resetPlaybackRate) video.playbackRate = 1;
video.play().catch((err) => {
toast.fire({ icon: 'error', text: 'Unable to play this file. Try to convert to friendly format first' });
toast.fire({ icon: 'error', text: 'Unable to play this file. Try to convert to supported format first' });
console.error(err);
});
}, [playing, filePath]);
@ -1109,7 +1109,7 @@ const App = memo(() => {
const existing = getHtml5ifiedPath(cod, fp, speed);
const ret = existing && await exists(existing);
if (ret) {
console.log('Found existing friendly file', existing);
console.log('Found existing supported file', existing);
if (speed === 'fastest-audio') {
setDummyVideoPath(existing);
setHtml5FriendlyPath();
@ -1163,6 +1163,10 @@ const App = memo(() => {
setDetectedFileFormat(ff);
setFileFormatData(fd);
if (!isAudioSupported(streams)) {
toast.fire({ icon: 'info', text: 'The audio track is not supported. You can convert to a supported format from the menu' });
}
if (html5FriendlyPathRequested) {
setHtml5FriendlyPath(html5FriendlyPathRequested);
showUnsupportedFileMessage();
@ -1507,7 +1511,7 @@ const App = memo(() => {
}
async function batchConvertFriendlyFormat() {
const title = i18n.t('Select files to batch convert to friendly format');
const title = i18n.t('Select files to batch convert to supported format');
const { canceled, filePaths } = await dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'], title, message: title });
if (canceled || filePaths.length < 1) return;
@ -1544,7 +1548,7 @@ const App = memo(() => {
if (failedFiles.length > 0) toast.fire({ title: `${i18n.t('Failed to convert files:')} ${failedFiles.join(' ')}`, timer: null, showConfirmButton: true });
} catch (err) {
errorToast(i18n.t('Failed to batch convert to friendly format'));
errorToast(i18n.t('Failed to batch convert to supported format'));
console.error('Failed to html5ify', err);
} finally {
setWorking();

@ -726,6 +726,13 @@ export function isStreamThumbnail(stream) {
return stream && stream.disposition && stream.disposition.attached_pic === 1;
}
export function isAudioSupported(streams) {
const audioStreams = streams.filter(stream => stream.codec_type === 'audio');
if (audioStreams.length === 0) return true;
// TODO this could be improved
return audioStreams.some(stream => !['ac3'].includes(stream.codec_name));
}
export function getStreamFps(stream) {
const match = typeof stream.avg_frame_rate === 'string' && stream.avg_frame_rate.match(/^([0-9]+)\/([0-9]+)$/);
if (stream.codec_type === 'video' && match) {

Loading…
Cancel
Save