Skip to content

Commit

Permalink
add some hevc support checking
Browse files Browse the repository at this point in the history
  • Loading branch information
mifi committed Jan 5, 2023
1 parent 97ba07d commit c5b3885
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
10 changes: 7 additions & 3 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import {
getDuration, getTimecodeFromStreams, createChaptersFromSegments, extractSubtitleTrack,
RefuseOverwriteError, readFrames, mapTimesToSegments,
} from './ffmpeg';
import { shouldCopyStreamByDefault, getAudioStreams, getRealVideoStreams, isAudioDefinitelyNotSupported, doesPlayerSupportFile } from './util/streams';
import { shouldCopyStreamByDefault, getAudioStreams, getRealVideoStreams, isAudioDefinitelyNotSupported, willPlayerProperlyHandleVideo, doesPlayerSupportHevcPlayback } from './util/streams';
import { exportEdlFile, readEdlFile, saveLlcProject, loadLlcProject, askForEdlImport } from './edlStore';
import { formatYouTube, getFrameCountRaw } from './edlFormats';
import {
Expand Down Expand Up @@ -99,6 +99,8 @@ const videoStyle = { width: '100%', height: '100%', objectFit: 'contain' };
const bottomMotionStyle = { background: controlsBackground };

let lastOpenedPath;
const hevcPlaybackSupportedPromise = doesPlayerSupportHevcPlayback();
hevcPlaybackSupportedPromise.catch((err) => console.error(err));

const App = memo(() => {
// Per project state
Expand Down Expand Up @@ -1596,8 +1598,10 @@ const App = memo(() => {
const validDuration = isDurationValid(parseFloat(fileMeta.format.duration));
const hasLoadedExistingHtml5FriendlyFile = await checkAndSetExistingHtml5FriendlyFile();

const hevcPlaybackSupported = await hevcPlaybackSupportedPromise;

// 'fastest' works with almost all video files
if (!hasLoadedExistingHtml5FriendlyFile && !doesPlayerSupportFile(fileMeta.streams) && validDuration) {
if (!hasLoadedExistingHtml5FriendlyFile && !willPlayerProperlyHandleVideo({ streams: fileMeta.streams, hevcPlaybackSupported }) && validDuration) {
await html5ifyAndLoadWithPreferences(cod, fp, 'fastest', haveVideoStream, haveAudioStream);
}

Expand Down Expand Up @@ -2211,7 +2215,7 @@ const App = memo(() => {

try {
const PIPELINE_ERROR_DECODE = 3; // This usually happens when the user presses play or seeks, but the video is not actually playable. To reproduce: "RX100VII PCM audio timecode.MP4" or see https://github.com/mifi/lossless-cut/issues/804
const MEDIA_ERR_SRC_NOT_SUPPORTED = 4; // Test: issue-668-3.20.1.m2ts - NOTE: DEMUXER_ERROR_COULD_NOT_OPEN is also 4
const MEDIA_ERR_SRC_NOT_SUPPORTED = 4; // Test: issue-668-3.20.1.m2ts - NOTE: DEMUXER_ERROR_COULD_NOT_OPEN and DEMUXER_ERROR_NO_SUPPORTED_STREAMS is also 4
if (!([MEDIA_ERR_SRC_NOT_SUPPORTED, PIPELINE_ERROR_DECODE].includes(error.code) && !usingPreviewFile && filePath)) return;

if (workingRef.current) return;
Expand Down
31 changes: 27 additions & 4 deletions src/util/streams.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,17 +223,40 @@ export function getStreamIdsToCopy({ streams, includeAllStreams }) {
return ret;
}

// With these codecs, the player will not give a playback error, but instead only play audio,
// this is just a rough check, could be improved
// todo check more accurately based on actual video stream
// https://github.com/StaZhu/enable-chromium-hevc-hardware-decoding#how-to-verify-certain-profile-or-resolution-is-supported
// https://github.com/mifi/lossless-cut/issues/88#issuecomment-1363828563
export async function doesPlayerSupportHevcPlayback() {
const { supported } = await navigator.mediaCapabilities.decodingInfo({
type: 'file',
video: {
contentType: 'video/mp4; codecs="hev1.1.6.L93.B0"', // Main
width: 1920,
height: 1080,
bitrate: 10000,
framerate: 30,
},
});
return supported;
}

// With some codecs, the player will not give a playback error, but instead only play audio,
// so we will detect these codecs and convert to dummy
export function doesPlayerSupportFile(streams) {
// "properly handle" here means either play it back or give a playback error if the video codec is not supported
// todo maybe improve https://github.com/mifi/lossless-cut/issues/88#issuecomment-1363828563
export function willPlayerProperlyHandleVideo({ streams, hevcPlaybackSupported }) {
const realVideoStreams = getRealVideoStreams(streams);
// If audio-only format, assume all is OK
if (realVideoStreams.length === 0) return true;
// If we have at least one video that is NOT of the unsupported formats, assume the player will be able to play it natively
// But cover art / thumbnail streams don't count e.g. hevc with a png stream (disposition.attached_pic=1)
// https://github.com/mifi/lossless-cut/issues/595
// https://github.com/mifi/lossless-cut/issues/975
// But cover art / thumbnail streams don't count e.g. hevc with a png stream (disposition.attached_pic=1)
return realVideoStreams.some(s => !['prores', 'mpeg4', 'tscc2', 'dvvideo'].includes(s.codec_name));
// https://github.com/mifi/lossless-cut/issues/1407
const chromiumSilentlyFailCodecs = ['prores', 'mpeg4', 'tscc2', 'dvvideo'];
if (!hevcPlaybackSupported) chromiumSilentlyFailCodecs.push('hevc');
return realVideoStreams.some((stream) => !chromiumSilentlyFailCodecs.includes(stream.codec_name));
}

export function isAudioDefinitelyNotSupported(streams) {
Expand Down

0 comments on commit c5b3885

Please sign in to comment.