@@ -3,11 +3,16 @@ import {getDefaultOutLocation} from '@remotion/studio-shared';
33import type {
44 RenderMediaOnWebProgress ,
55 RenderStillOnWebImageFormat ,
6+ WebRendererAudioCodec ,
67 WebRendererContainer ,
78 WebRendererQuality ,
89 WebRendererVideoCodec ,
910} from '@remotion/web-renderer' ;
10- import { renderMediaOnWeb , renderStillOnWeb } from '@remotion/web-renderer' ;
11+ import {
12+ getDefaultAudioCodecForContainer ,
13+ renderMediaOnWeb ,
14+ renderStillOnWeb ,
15+ } from '@remotion/web-renderer' ;
1116import { useCallback , useContext , useMemo , useState } from 'react' ;
1217import { ShortcutHint } from '../../error-overlay/remotion-overlay/ShortcutHint' ;
1318import { AudioIcon } from '../../icons/audio' ;
@@ -42,6 +47,8 @@ import {
4247 ResolveCompositionBeforeModal ,
4348 ResolvedCompositionContext ,
4449} from './ResolveCompositionBeforeModal' ;
50+ import { useEncodableAudioCodecs } from './use-encodable-audio-codecs' ;
51+ import { useEncodableVideoCodecs } from './use-encodable-video-codecs' ;
4552import { WebRendererExperimentalBadge } from './WebRendererExperimentalBadge' ;
4653import { WebRenderModalAdvanced } from './WebRenderModalAdvanced' ;
4754import { WebRenderModalAudio } from './WebRenderModalAudio' ;
@@ -185,6 +192,9 @@ const WebRenderModal: React.FC<WebRenderModalProps> = ({
185192 // Video-specific state
186193 const [ codec , setCodec ] = useState < WebRendererVideoCodec > ( 'h264' ) ;
187194 const [ container , setContainer ] = useState < WebRendererContainer > ( 'mp4' ) ;
195+ const [ audioCodec , setAudioCodec ] = useState < WebRendererAudioCodec > ( 'aac' ) ;
196+ const [ audioBitrate , setAudioBitrate ] =
197+ useState < WebRendererQuality > ( 'medium' ) ;
188198 const [ videoBitrate , setVideoBitrate ] = useState < WebRendererQuality > ( 'high' ) ;
189199 const [ hardwareAcceleration , setHardwareAcceleration ] = useState <
190200 'no-preference' | 'prefer-hardware' | 'prefer-software'
@@ -203,6 +213,25 @@ const WebRenderModal: React.FC<WebRenderModalProps> = ({
203213
204214 const [ licenseKey , setLicenseKey ] = useState ( initialLicenseKey ) ;
205215
216+ const encodableAudioCodecs = useEncodableAudioCodecs ( container ) ;
217+ const encodableVideoCodecs = useEncodableVideoCodecs ( container ) ;
218+
219+ const effectiveAudioCodec = useMemo ( ( ) : WebRendererAudioCodec => {
220+ if ( encodableAudioCodecs . includes ( audioCodec ) ) {
221+ return audioCodec ;
222+ }
223+
224+ return encodableAudioCodecs [ 0 ] ?? audioCodec ;
225+ } , [ audioCodec , encodableAudioCodecs ] ) ;
226+
227+ const effectiveVideoCodec = useMemo ( ( ) : WebRendererVideoCodec => {
228+ if ( encodableVideoCodecs . includes ( codec ) ) {
229+ return codec ;
230+ }
231+
232+ return encodableVideoCodecs [ 0 ] ?? codec ;
233+ } , [ codec , encodableVideoCodecs ] ) ;
234+
206235 const finalEndFrame = useMemo ( ( ) => {
207236 if ( endFrame === null ) {
208237 return resolvedComposition . durationInFrames - 1 ;
@@ -258,6 +287,7 @@ const WebRenderModal: React.FC<WebRenderModalProps> = ({
258287 const setContainerFormat = useCallback (
259288 ( newContainer : WebRendererContainer ) => {
260289 setContainer ( newContainer ) ;
290+ setAudioCodec ( getDefaultAudioCodecForContainer ( newContainer ) ) ;
261291 setOutName ( ( prev ) => {
262292 const newFileName = getStringBeforeSuffix ( prev ) + '.' + newContainer ;
263293 return newFileName ;
@@ -274,7 +304,7 @@ const WebRenderModal: React.FC<WebRenderModalProps> = ({
274304 const newFileName = getStringBeforeSuffix ( prev ) + '.' + container ;
275305 return newFileName ;
276306 } ) ;
277- } else {
307+ } else if ( newMode === 'still' ) {
278308 setOutName ( ( prev ) => {
279309 const newFileName = getStringBeforeSuffix ( prev ) + '.' + imageFormat ;
280310 return newFileName ;
@@ -461,7 +491,9 @@ const WebRenderModal: React.FC<WebRenderModalProps> = ({
461491 delayRenderTimeoutInMilliseconds : delayRenderTimeout ,
462492 mediaCacheSizeInBytes,
463493 logLevel,
464- videoCodec : codec ,
494+ videoCodec : effectiveVideoCodec ,
495+ audioCodec : effectiveAudioCodec ,
496+ audioBitrate,
465497 container,
466498 videoBitrate,
467499 hardwareAcceleration,
@@ -495,7 +527,9 @@ const WebRenderModal: React.FC<WebRenderModalProps> = ({
495527 delayRenderTimeout ,
496528 mediaCacheSizeInBytes ,
497529 logLevel ,
498- codec ,
530+ effectiveVideoCodec ,
531+ effectiveAudioCodec ,
532+ audioBitrate ,
499533 container ,
500534 videoBitrate ,
501535 hardwareAcceleration ,
@@ -623,8 +657,9 @@ const WebRenderModal: React.FC<WebRenderModalProps> = ({
623657 onFrameSetDirectly = { onFrameSetDirectly }
624658 container = { container }
625659 setContainerFormat = { setContainerFormat }
626- codec = { codec }
627660 setCodec = { setCodec }
661+ encodableVideoCodecs = { encodableVideoCodecs }
662+ effectiveVideoCodec = { effectiveVideoCodec }
628663 startFrame = { finalStartFrame }
629664 setStartFrame = { setStartFrame }
630665 endFrame = { finalEndFrame }
@@ -659,7 +694,17 @@ const WebRenderModal: React.FC<WebRenderModalProps> = ({
659694 setTransparent = { setTransparent }
660695 />
661696 ) : tab === 'audio' ? (
662- < WebRenderModalAudio muted = { muted } setMuted = { setMuted } />
697+ < WebRenderModalAudio
698+ muted = { muted }
699+ setMuted = { setMuted }
700+ audioCodec = { audioCodec }
701+ setAudioCodec = { setAudioCodec }
702+ audioBitrate = { audioBitrate }
703+ setAudioBitrate = { setAudioBitrate }
704+ container = { container }
705+ encodableCodecs = { encodableAudioCodecs }
706+ effectiveAudioCodec = { effectiveAudioCodec }
707+ />
663708 ) : tab === 'advanced' ? (
664709 < WebRenderModalAdvanced
665710 renderMode = { renderMode }
0 commit comments