avm2: Actually create an unconnected `Video` when one is constructed via `new Video`
This commit is contained in:
parent
c86360a10b
commit
f690162a4f
|
@ -13,8 +13,11 @@ package flash.media
|
||||||
public function Video(width: int = 320, height: int = 240) {
|
public function Video(width: int = 320, height: int = 240) {
|
||||||
this._videoWidth = width;
|
this._videoWidth = width;
|
||||||
this._videoHeight = height;
|
this._videoHeight = height;
|
||||||
|
this.init(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private native function init(width: int, height: int);
|
||||||
|
|
||||||
public function get deblocking():int {
|
public function get deblocking():int {
|
||||||
return this._deblocking;
|
return this._deblocking;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,42 @@
|
||||||
use crate::avm2::{Activation, Error, Object, TObject, Value};
|
use crate::avm2::{Activation, Error, Object, TObject, Value};
|
||||||
use crate::display_object::TDisplayObject;
|
use crate::display_object::{TDisplayObject, Video};
|
||||||
|
|
||||||
|
/// Implements `flash.media.Video`'s `init` method, which is called from the constructor
|
||||||
|
pub fn init<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
this: Option<Object<'gc>>,
|
||||||
|
args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
if let Some(this) = this {
|
||||||
|
activation.super_init(this, &[])?;
|
||||||
|
|
||||||
|
if this.as_display_object().is_none() {
|
||||||
|
let width = args
|
||||||
|
.get(0)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(Value::Undefined)
|
||||||
|
.coerce_to_i32(activation)?;
|
||||||
|
let height = args
|
||||||
|
.get(1)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(Value::Undefined)
|
||||||
|
.coerce_to_i32(activation)?;
|
||||||
|
|
||||||
|
let movie = activation.context.swf.clone();
|
||||||
|
let new_do = Video::new(
|
||||||
|
activation.context.gc_context,
|
||||||
|
movie,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
Some(this.into()),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.init_display_object(&mut activation.context, new_do.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn attach_net_stream<'gc>(
|
pub fn attach_net_stream<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
|
|
@ -63,6 +63,9 @@ pub struct VideoData<'gc> {
|
||||||
/// the prior keyframe. The first frame in the stream will always be
|
/// the prior keyframe. The first frame in the stream will always be
|
||||||
/// treated as a keyframe regardless of it being flagged as one.
|
/// treated as a keyframe regardless of it being flagged as one.
|
||||||
keyframes: BTreeSet<u32>,
|
keyframes: BTreeSet<u32>,
|
||||||
|
|
||||||
|
/// The movie whose tagstream or code created the Video object.
|
||||||
|
movie: Arc<SwfMovie>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An optionally-instantiated video stream.
|
/// An optionally-instantiated video stream.
|
||||||
|
@ -84,9 +87,6 @@ pub enum VideoStream {
|
||||||
pub enum VideoSource<'gc> {
|
pub enum VideoSource<'gc> {
|
||||||
/// A video bitstream embedded inside of a SWF movie.
|
/// A video bitstream embedded inside of a SWF movie.
|
||||||
Swf {
|
Swf {
|
||||||
/// The movie that defined this video stream.
|
|
||||||
movie: Arc<SwfMovie>,
|
|
||||||
|
|
||||||
/// The video stream definition.
|
/// The video stream definition.
|
||||||
#[collect(require_static)]
|
#[collect(require_static)]
|
||||||
streamdef: DefineVideoStream,
|
streamdef: DefineVideoStream,
|
||||||
|
@ -103,12 +103,12 @@ pub enum VideoSource<'gc> {
|
||||||
},
|
},
|
||||||
/// An attached NetStream.
|
/// An attached NetStream.
|
||||||
NetStream {
|
NetStream {
|
||||||
/// The movie whose code created the Video object.
|
|
||||||
movie: Arc<SwfMovie>,
|
|
||||||
|
|
||||||
/// The stream the video is downloaded from.
|
/// The stream the video is downloaded from.
|
||||||
stream: NetStream<'gc>,
|
stream: NetStream<'gc>,
|
||||||
},
|
},
|
||||||
|
Unconnected {
|
||||||
|
size: (i32, i32),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Video<'gc> {
|
impl<'gc> Video<'gc> {
|
||||||
|
@ -121,7 +121,6 @@ impl<'gc> Video<'gc> {
|
||||||
let source = GcCell::allocate(
|
let source = GcCell::allocate(
|
||||||
mc,
|
mc,
|
||||||
VideoSource::Swf {
|
VideoSource::Swf {
|
||||||
movie,
|
|
||||||
streamdef,
|
streamdef,
|
||||||
frames: BTreeMap::new(),
|
frames: BTreeMap::new(),
|
||||||
decoded_frame: None,
|
decoded_frame: None,
|
||||||
|
@ -136,6 +135,34 @@ impl<'gc> Video<'gc> {
|
||||||
stream: VideoStream::Uninstantiated(0),
|
stream: VideoStream::Uninstantiated(0),
|
||||||
object: None,
|
object: None,
|
||||||
keyframes: BTreeSet::new(),
|
keyframes: BTreeSet::new(),
|
||||||
|
movie,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
mc: MutationContext<'gc, '_>,
|
||||||
|
movie: Arc<SwfMovie>,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
object: Option<AvmObject<'gc>>,
|
||||||
|
) -> Self {
|
||||||
|
let source = GcCell::allocate(
|
||||||
|
mc,
|
||||||
|
VideoSource::Unconnected {
|
||||||
|
size: (width, height),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Video(GcCell::allocate(
|
||||||
|
mc,
|
||||||
|
VideoData {
|
||||||
|
base: Default::default(),
|
||||||
|
source,
|
||||||
|
stream: VideoStream::Uninstantiated(0),
|
||||||
|
object,
|
||||||
|
keyframes: BTreeSet::new(),
|
||||||
|
movie,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -144,10 +171,9 @@ impl<'gc> Video<'gc> {
|
||||||
///
|
///
|
||||||
/// Existing video state related to the old video stream will be dropped.
|
/// Existing video state related to the old video stream will be dropped.
|
||||||
pub fn attach_netstream(self, context: &mut UpdateContext<'_, 'gc>, stream: NetStream<'gc>) {
|
pub fn attach_netstream(self, context: &mut UpdateContext<'_, 'gc>, stream: NetStream<'gc>) {
|
||||||
let movie = self.movie();
|
|
||||||
let mut video = self.0.write(context.gc_context);
|
let mut video = self.0.write(context.gc_context);
|
||||||
|
|
||||||
*video.source.write(context.gc_context) = VideoSource::NetStream { movie, stream };
|
*video.source.write(context.gc_context) = VideoSource::NetStream { stream };
|
||||||
|
|
||||||
video.stream = VideoStream::Uninstantiated(0);
|
video.stream = VideoStream::Uninstantiated(0);
|
||||||
video.keyframes = BTreeSet::new();
|
video.keyframes = BTreeSet::new();
|
||||||
|
@ -158,6 +184,8 @@ impl<'gc> Video<'gc> {
|
||||||
/// This function yields an error if this video player is not playing an
|
/// This function yields an error if this video player is not playing an
|
||||||
/// embedded SWF video.
|
/// embedded SWF video.
|
||||||
pub fn preload_swf_frame(&mut self, tag: VideoFrame, context: &mut UpdateContext<'_, 'gc>) {
|
pub fn preload_swf_frame(&mut self, tag: VideoFrame, context: &mut UpdateContext<'_, 'gc>) {
|
||||||
|
let movie = self.0.read().movie.clone();
|
||||||
|
|
||||||
match (*self
|
match (*self
|
||||||
.0
|
.0
|
||||||
.write(context.gc_context)
|
.write(context.gc_context)
|
||||||
|
@ -165,8 +193,8 @@ impl<'gc> Video<'gc> {
|
||||||
.write(context.gc_context))
|
.write(context.gc_context))
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
{
|
{
|
||||||
VideoSource::Swf { movie, frames, .. } => {
|
VideoSource::Swf { frames, .. } => {
|
||||||
let subslice = SwfSlice::from(movie.clone()).to_unbounded_subslice(tag.data);
|
let subslice = SwfSlice::from(movie).to_unbounded_subslice(tag.data);
|
||||||
|
|
||||||
if frames.contains_key(&tag.frame_num.into()) {
|
if frames.contains_key(&tag.frame_num.into()) {
|
||||||
tracing::warn!("Duplicate frame {}", tag.frame_num);
|
tracing::warn!("Duplicate frame {}", tag.frame_num);
|
||||||
|
@ -175,6 +203,7 @@ impl<'gc> Video<'gc> {
|
||||||
frames.insert(tag.frame_num.into(), (subslice.start, subslice.end));
|
frames.insert(tag.frame_num.into(), (subslice.start, subslice.end));
|
||||||
}
|
}
|
||||||
VideoSource::NetStream { .. } => {}
|
VideoSource::NetStream { .. } => {}
|
||||||
|
VideoSource::Unconnected { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +239,7 @@ impl<'gc> Video<'gc> {
|
||||||
..
|
..
|
||||||
} => (streamdef.num_frames as usize, decoded_frame.clone()),
|
} => (streamdef.num_frames as usize, decoded_frame.clone()),
|
||||||
VideoSource::NetStream { .. } => return,
|
VideoSource::NetStream { .. } => return,
|
||||||
|
VideoSource::Unconnected { .. } => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
frame_id = if num_frames > 0 {
|
frame_id = if num_frames > 0 {
|
||||||
|
@ -278,7 +308,6 @@ impl<'gc> Video<'gc> {
|
||||||
|
|
||||||
let res = match &*source.read() {
|
let res = match &*source.read() {
|
||||||
VideoSource::Swf {
|
VideoSource::Swf {
|
||||||
movie,
|
|
||||||
streamdef,
|
streamdef,
|
||||||
frames,
|
frames,
|
||||||
decoded_frame,
|
decoded_frame,
|
||||||
|
@ -286,7 +315,7 @@ impl<'gc> Video<'gc> {
|
||||||
Some((slice_start, slice_end)) => {
|
Some((slice_start, slice_end)) => {
|
||||||
let encframe = EncodedFrame {
|
let encframe = EncodedFrame {
|
||||||
codec: streamdef.codec,
|
codec: streamdef.codec,
|
||||||
data: &movie.data()[*slice_start..*slice_end],
|
data: &read.movie.data()[*slice_start..*slice_end],
|
||||||
frame_id,
|
frame_id,
|
||||||
};
|
};
|
||||||
context
|
context
|
||||||
|
@ -302,6 +331,7 @@ impl<'gc> Video<'gc> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
VideoSource::NetStream { .. } => return,
|
VideoSource::NetStream { .. } => return,
|
||||||
|
VideoSource::Unconnected { .. } => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
drop(read);
|
drop(read);
|
||||||
|
@ -310,6 +340,7 @@ impl<'gc> Video<'gc> {
|
||||||
Ok(bitmap) => match &mut *source.write(context.gc_context) {
|
Ok(bitmap) => match &mut *source.write(context.gc_context) {
|
||||||
VideoSource::Swf { decoded_frame, .. } => *decoded_frame = Some((frame_id, bitmap)),
|
VideoSource::Swf { decoded_frame, .. } => *decoded_frame = Some((frame_id, bitmap)),
|
||||||
VideoSource::NetStream { .. } => unreachable!(),
|
VideoSource::NetStream { .. } => unreachable!(),
|
||||||
|
VideoSource::Unconnected { .. } => unreachable!(),
|
||||||
},
|
},
|
||||||
Err(e) => tracing::error!("Got error when seeking to video frame {}: {}", frame_id, e),
|
Err(e) => tracing::error!("Got error when seeking to video frame {}: {}", frame_id, e),
|
||||||
}
|
}
|
||||||
|
@ -351,13 +382,11 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut write = self.0.write(context.gc_context);
|
let mut write = self.0.write(context.gc_context);
|
||||||
|
let movie = write.movie.clone();
|
||||||
|
|
||||||
let (stream, movie, keyframes) = match &*write.source.read() {
|
let (stream, keyframes) = match &*write.source.read() {
|
||||||
VideoSource::Swf {
|
VideoSource::Swf {
|
||||||
streamdef,
|
streamdef, frames, ..
|
||||||
movie,
|
|
||||||
frames,
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
let stream = context.video.register_video_stream(
|
let stream = context.video.register_video_stream(
|
||||||
streamdef.num_frames.into(),
|
streamdef.num_frames.into(),
|
||||||
|
@ -397,9 +426,10 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(stream, movie.clone(), keyframes)
|
(stream, keyframes)
|
||||||
}
|
}
|
||||||
VideoSource::NetStream { .. } => return,
|
VideoSource::NetStream { .. } => return,
|
||||||
|
VideoSource::Unconnected { .. } => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let starting_seek = if let VideoStream::Uninstantiated(seek_to) = write.stream {
|
let starting_seek = if let VideoStream::Uninstantiated(seek_to) = write.stream {
|
||||||
|
@ -456,6 +486,7 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> {
|
||||||
match &*self.0.read().source.read() {
|
match &*self.0.read().source.read() {
|
||||||
VideoSource::Swf { streamdef, .. } => streamdef.id,
|
VideoSource::Swf { streamdef, .. } => streamdef.id,
|
||||||
VideoSource::NetStream { .. } => 0,
|
VideoSource::NetStream { .. } => 0,
|
||||||
|
VideoSource::Unconnected { .. } => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,6 +507,12 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> {
|
||||||
y_max: Twips::from_pixels_i32(bm.height as u32 as i32),
|
y_max: Twips::from_pixels_i32(bm.height as u32 as i32),
|
||||||
})
|
})
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
VideoSource::Unconnected { size } => Rectangle {
|
||||||
|
x_min: Twips::ZERO,
|
||||||
|
x_max: Twips::from_pixels_i32(size.0),
|
||||||
|
y_min: Twips::ZERO,
|
||||||
|
y_max: Twips::from_pixels_i32(size.1),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,20 +534,20 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> {
|
||||||
VideoSource::Swf {
|
VideoSource::Swf {
|
||||||
streamdef,
|
streamdef,
|
||||||
frames,
|
frames,
|
||||||
movie,
|
|
||||||
decoded_frame,
|
decoded_frame,
|
||||||
} => (
|
} => (
|
||||||
streamdef.is_smoothed,
|
streamdef.is_smoothed,
|
||||||
Some(frames.len()),
|
Some(frames.len()),
|
||||||
movie.version(),
|
read.movie.version(),
|
||||||
decoded_frame.clone().map(|df| df.1),
|
decoded_frame.clone().map(|df| df.1),
|
||||||
),
|
),
|
||||||
VideoSource::NetStream { stream, .. } => (
|
VideoSource::NetStream { stream, .. } => (
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
self.movie().version(),
|
read.movie.version(),
|
||||||
stream.last_decoded_bitmap(),
|
stream.last_decoded_bitmap(),
|
||||||
),
|
),
|
||||||
|
VideoSource::Unconnected { .. } => return context.transform_stack.pop(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let smoothing = match (context.stage.quality(), version) {
|
let smoothing = match (context.stage.quality(), version) {
|
||||||
|
@ -544,9 +581,6 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn movie(&self) -> Arc<SwfMovie> {
|
fn movie(&self) -> Arc<SwfMovie> {
|
||||||
match &*self.0.read().source.read() {
|
self.0.read().movie.clone()
|
||||||
VideoSource::Swf { movie, .. } => movie.clone(),
|
|
||||||
VideoSource::NetStream { movie, .. } => movie.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue