2828
2929#import < Foundation/NSArray.h>
3030#import < Foundation/NSData.h>
31+ #import < Foundation/NSTimer.h>
3132#import < Foundation/NSURL.h>
33+
34+ #import " AppKit/NSColor.h"
35+ #import " AppKit/NSGraphics.h"
36+ #import " AppKit/NSImage.h"
37+ #import " AppKit/NSImageRep.h"
3238#import " AppKit/NSMovie.h"
3339#import " AppKit/NSMovieView.h"
3440#import " AppKit/NSPasteboard.h"
3541
3642@implementation NSMovieView
3743
44+ // private method to display frames...
45+ - (void ) _updateImage : (NSImage *)image
46+ {
47+ _currentFrame = image;
48+ [self setNeedsDisplay: YES ];
49+ }
50+
51+ - (void ) _prepareDecoder
52+ {
53+ NSString *moviePath = [[_movie URL ] path ];
54+
55+ _formatContext = avformat_alloc_context ();
56+ if (avformat_open_input (&_formatContext, [moviePath UTF8String ], NULL , NULL ) != 0 ) return ;
57+ if (avformat_find_stream_info (_formatContext, NULL ) < 0 ) return ;
58+
59+ _videoStreamIndex = -1 ;
60+ for (int i = 0 ; i < _formatContext->nb_streams ; i++)
61+ {
62+ if (_formatContext->streams [i]->codecpar ->codec_type == AVMEDIA_TYPE_VIDEO)
63+ {
64+ _videoStreamIndex = i;
65+ break ;
66+ }
67+ }
68+
69+ if (_videoStreamIndex == -1 ) return ;
70+
71+ AVCodecParameters *codecPar = _formatContext->streams [_videoStreamIndex]->codecpar ;
72+ const AVCodec *codec = avcodec_find_decoder (codecPar->codec_id );
73+
74+ _codecContext = avcodec_alloc_context3 (codec);
75+ avcodec_parameters_to_context (_codecContext, codecPar);
76+ if (avcodec_open2 (_codecContext, codec, NULL ) < 0 ) return ;
77+
78+ _avframe = av_frame_alloc ();
79+ _avframeRGB = av_frame_alloc ();
80+
81+ int numBytes = av_image_get_buffer_size (AV_PIX_FMT_RGB24, _codecContext->width , _codecContext->height , 1 );
82+ _buffer = (uint8_t *)av_malloc (numBytes * sizeof (uint8_t ));
83+ av_image_fill_arrays (_avframeRGB->data , _avframeRGB->linesize , _buffer, AV_PIX_FMT_RGB24,
84+ _codecContext->width , _codecContext->height , 1 );
85+
86+ _swsCtx = sws_getContext (_codecContext->width , _codecContext->height , _codecContext->pix_fmt ,
87+ _codecContext->width , _codecContext->height , AV_PIX_FMT_RGB24,
88+ SWS_BILINEAR, NULL , NULL , NULL );
89+
90+ }
91+
92+ - (void ) _decodeAndDisplayNextFrame
93+ {
94+ AVPacket packet;
95+
96+ av_init_packet (&packet);
97+ packet.data = NULL ;
98+ packet.size = 0 ;
99+
100+ while (av_read_frame (_formatContext, &packet) >= 0 )
101+ {
102+ if (!_playing) break ;
103+
104+ if (packet.stream_index == _videoStreamIndex)
105+ {
106+ avcodec_send_packet (_codecContext, &packet);
107+ if (avcodec_receive_frame (_codecContext, _avframe) == 0 )
108+ {
109+ sws_scale (_swsCtx, (const uint8_t * const *)_avframe->data , _avframe->linesize , 0 ,
110+ _codecContext->height , _avframeRGB->data , _avframeRGB->linesize );
111+
112+ NSBitmapImageRep *rep = [[NSBitmapImageRep alloc ]
113+ initWithBitmapDataPlanes: _avframeRGB->data
114+ pixelsWide: _codecContext->width
115+ pixelsHigh: _codecContext->height
116+ bitsPerSample: 8
117+ samplesPerPixel: 3
118+ hasAlpha: NO
119+ isPlanar: NO
120+ colorSpaceName: NSCalibratedRGBColorSpace
121+ bytesPerRow: _avframeRGB->linesize[0 ]
122+ bitsPerPixel: 24 ];
123+
124+ NSImage *image = [[NSImage alloc ] initWithSize: NSMakeSize (_codecContext->width, _codecContext->height)];
125+ [image addRepresentation: rep];
126+
127+ [self performSelectorOnMainThread: @selector (_updateImage: )
128+ withObject: image
129+ waitUntilDone: NO ];
130+ break ;
131+ }
132+ }
133+ av_packet_unref (&packet);
134+ }
135+ }
136+
137+ - (void ) drawRect : (NSRect )dirtyRect
138+ {
139+ [super drawRect: dirtyRect];
140+ if (_currentFrame)
141+ {
142+ [_currentFrame drawInRect: [self bounds ]];
143+ }
144+ }
145+
38146- (void ) setMovie : (NSMovie *)movie
39147{
40148 ASSIGN (_movie, movie);
149+ [self _prepareDecoder ];
41150}
42151
43152- (NSMovie *) movie
@@ -47,18 +156,39 @@ - (NSMovie*) movie
47156
48157- (void ) start : (id )sender
49158{
50- // FIXME
159+ _playing = YES ;
160+ _rate = 1.0 / 30.0 ;
161+ _volume = 1.0 ;
162+
163+ _decodeTimer =
164+ [NSTimer scheduledTimerWithTimeInterval: _rate
165+ target: self
166+ selector: @selector (decodeAndDisplayNextFrame )
167+ userInfo: nil
168+ repeats: YES ];
51169}
52170
53171- (void ) stop : (id )sender
54172{
55- // FIXME
173+ _playing = NO ;
174+
175+ if (_decodeTimer)
176+ {
177+ [_decodeTimer invalidate ];
178+ _decodeTimer = nil ;
179+ }
180+
181+ if (_avframe) av_frame_free (&_avframe);
182+ if (_avframeRGB) av_frame_free (&_avframeRGB);
183+ if (_buffer) av_free (_buffer);
184+ if (_codecContext) avcodec_free_context (&_codecContext);
185+ if (_formatContext) avformat_close_input (&_formatContext);
186+ if (_swsCtx) sws_freeContext (_swsCtx);
56187}
57188
58189- (BOOL ) isPlaying
59190{
60- // FIXME
61- return NO ;
191+ return _playing;
62192}
63193
64194- (void ) gotoPosterFrame : (id )sender
0 commit comments