diff --git a/dev/convert.html b/dev/convert.html index e548520..36a2645 100644 --- a/dev/convert.html +++ b/dev/convert.html @@ -100,9 +100,10 @@ }, */ video: () => ({ - width: 720, - frameRate: 30, - bitrate: Mediabunny.QUALITY_VERY_LOW, + allowRotationMetadata: false, + //width: 720, + //frameRate: 30, + //bitrate: Mediabunny.QUALITY_VERY_LOW, //discard: true, /* process: (sample) => { @@ -180,7 +181,7 @@ }, trim: { start: 0, - end: 20 + end: 4 }, }); console.log(conversion); diff --git a/docs/guide/converting-media-files.md b/docs/guide/converting-media-files.md index b54c9e1..c527f12 100644 --- a/docs/guide/converting-media-files.md +++ b/docs/guide/converting-media-files.md @@ -120,6 +120,7 @@ type ConversionVideoOptions = { height?: number; fit?: 'fill' | 'contain' | 'cover'; rotate?: 0 | 90 | 180 | 270; + allowRotationMetadata?: boolean; crop?: { left: number; top: number; width: number; height: number }; frameRate?: number; codec?: VideoCodec; @@ -175,6 +176,8 @@ In the rare case that the input video changes size over time, the `fit` field ca `rotation` rotates the video by the specified number of degrees clockwise. This rotation is applied on top of any rotation metadata in the original input file and happens before cropping and resizing. +By default, Mediabunny will try to make use of rotation metadata in the output file to perform the rotation whenever possible. However, if you don't want this to happen, or you want to use Mediabunny to strip all rotation metadata from a file, you can set `allowRotationMetadata` to `false`. + ### Cropping video `crop` can be used to extract a rectangular region from the original video. The rectangle is specified using `left`, `top`, `width` and `height` and is clamped to the dimensions of the video. Cropping is applied after rotation but before resizing. diff --git a/src/conversion.ts b/src/conversion.ts index 59ccada..6ea8994 100644 --- a/src/conversion.ts +++ b/src/conversion.ts @@ -143,6 +143,12 @@ export type ConversionVideoOptions = { * This rotation is _in addition to_ the natural rotation of the input video as specified in input file's metadata. */ rotate?: Rotation; + /** + * Defaults to `true`. When enabaled, Mediabunny will use the rotation metadata in the output file to perform video + * rotation whenever possible. Set this field to `false` if you want to ensure the output file does not make use of + * rotation metadata and that any rotation is baked into the video frames directly. + */ + allowRotationMetadata?: boolean; /** * Specifies the rectangular region of the input video to crop to. The crop region will automatically be clamped to * the dimensions of the input video track. Cropping is performed after rotation but before resizing. @@ -304,6 +310,9 @@ const validateVideoOptions = (videoOptions: ConversionVideoOptions | undefined) if (videoOptions?.rotate !== undefined && ![0, 90, 180, 270].includes(videoOptions.rotate)) { throw new TypeError('options.video.rotate, when provided, must be 0, 90, 180 or 270.'); } + if (videoOptions?.allowRotationMetadata !== undefined && typeof videoOptions.allowRotationMetadata !== 'boolean') { + throw new TypeError('options.video.allowRotationMetadata, when provided, must be a boolean.'); + } if (videoOptions?.crop !== undefined) { validateCropRectangle(videoOptions.crop, 'options.video.'); } @@ -838,7 +847,8 @@ export class Conversion { let videoSource: VideoSource; const totalRotation = normalizeRotation(track.rotation + (trackOptions.rotate ?? 0)); - const outputSupportsRotation = this.output.format.supportsVideoRotationMetadata; + const canUseRotationMetadata = this.output.format.supportsVideoRotationMetadata + && (trackOptions.allowRotationMetadata ?? true); const [rotatedWidth, rotatedHeight] = totalRotation % 180 === 0 ? [track.codedWidth, track.codedHeight] @@ -883,7 +893,7 @@ export class Conversion { // TODO This is suboptimal: Forcing a rerender when both rotation and process are set is not // performance-optimal, but right now there's no other way because we can't change the track rotation // metadata after the output has already started. Should be possible with API changes in v2, though! - || (totalRotation !== 0 && (!outputSupportsRotation || trackOptions.process !== undefined)) + || (totalRotation !== 0 && (!canUseRotationMetadata || trackOptions.process !== undefined)) || !!crop; const alpha = trackOptions.alpha ?? 'discard';