getPixels() not implemented in ofxAndroidVideoPlayer

Hi, I just noticed that getPixels() isn’t implemented in the ofxAndroidVideoPlayer. All I need to do is grab a frame of a video and display it as an image – I don’t need to modify the pixel data. This is what I was doing before (my_textures is just a vector of ofTextures):

ofTexture texture;
unsigned char *pixels = movies[i].getPixels();
texture.allocate( movies[i].getWidth(), movies[i].getHeight(), GL_RGB );
texture.loadData( pixels, movies[i].getWidth(), movies[i].getHeight(), GL_RGB );
my_textures.push_back( texture );        

What is the correct way to do this on Android? I see there is a getTexture() that returns a reference to a texture but I don’t see any way to turn that reference into a value. Is it a good idea to just modify the source of ofxAndroidVideoPlayer::getTexture() to return the texture itself instead of a reference to a texture?

All I need to do is display a single still from the movie after the movie has stopped playing (and been destroyed/deallocated).

Thanks!
Nick

Hi, I’m not too familiar with the particulars of the Android implementation, but if you can’t get at the pixels perhaps you can draw the video frame you want onto an FBO?

Best,
Andreas

Since you don’t want to modify the pixels, I think you should be able to copy the texture directly using the equals operator. Then again, I ran into segfaults when I tried to test it on my device…

Hmm, I tried the following approach:

ofTexture texture;
texture.allocate( movies[i].getWidth(), movies[i].getHeight(), GL_RGB );
texture = movies[i].getTextureReference();
my_textures.push_back( texture );

And it seems to work on OSX! I’ll have to give it a shot on Android.

Update:

getTextureReference() is also not implemented on Android… perhaps I can use the pointer returned from getTexture() instead?

ofTexture texture;
texture.allocate( movies[i].getWidth(), movies[i].getHeight(), GL_RGB );
texture = *(movies[i].getTexture())
my_textures.push_back( texture );

Ok, that crashes on OSX because for some reason getTexture() is hardcoded to return NULL in ofBaseVideoPlayer. Will give it a shot on Android though. I guess I can set it up so I use getTextureReference() on OSX and getTexture() on Android.

Update:

ofxAndroidPlayer::getTexture() seems to be returning an all-white texture. At this point I don’t know how to debug any further – with the standard Eclipse setup I can’t break into the code or inspect the OpenGL state like in iOS. I guess I’ll try the FBO approach now.

the android player draws to the screen using a texture only no pixels cause that’s the way android does it internally. in any case if you don’t need to access the pixels to do computer vision or any other operation on the cpu you can do it with the texture.

the texture should be accessible from ofVideoPlayer::getTexture() which will do the right thing. if you want to keep the texture around for more than one frame, though, it’s not as simple as copying the ofTexture object.

ofTexture makes internally a shallow copy meaning that it doesn’t really copy it’s data on the GPU but instead is just a reference to the original GL object so when you call update on the videoplayer again all the “copies” will be changed.

The easiest way is to just have a vector of fbos since it seems you want to have several textures and draw each video in one of them then you’ll have a copy of the texture in the internal texture that ofFbo holds.

there’s gl calls to blit one texture into another but there’s no direct support for that in OF yet

also take into account that the texture that android provides has a special target and a texture matrix to avoid in the gpu a padding that it adds to make uploading it faster so if you use it from a shader for example you’ll need to take that into account whch can be tricky

1 Like

Hi Arturto, thanks for the tips. I did end up using fbos, and that worked without the white texture problem – it probably was a shallow copy of ofTextures that caused that.

At this point, what I actually want to display is the final frame of each video but both ofVideoPlayer::setPosition(1.0) and ofVideoPlayer::setFrame(getTotalNumFrames()) are producing totally black frames that aren’t in the original video.

Is this also something that is specific to android’s video player? It seems to be working correctly on osx with the same videos.

just guessing, but I’d say there’s a frame 0. So you’d have to use

video.setFrame(video.getTotalNumFrames()-1);

to get the last frame.

I’ll give it a shot! It looks like both setFrame() and getTotalNumberFrames() are also not implemented in ofxAndroidVideoPlayer. I expect to see ofVideoBasePlayer::setFrame() log out an error message, about to try.

Is it required to call ofVideoPlayer::update() after using these methods?

Ok, so ofxAndroidVideoPlayer::setPosition() isn’t seeking to the end fast enough for me to grab the image:

movies[i].setPosition( 1.0 );
ofFbo fbo;
fbo.allocate( movies[i].getWidth(), movies[i].getHeight(), GL_RGB );
fbo.begin();
    movies[i].draw( 0, 0 );                        
fbo.end();
my_fbos.push_back( fbo );

I suppose it’s because MediaPlayer.seekTo(int) is asynchronous:

Note that the weird MediaPlayer state diagram is incorrect, seekTo() should have a double-arrowhead to indicate asynchrounous:

http://developer.android.com/reference/android/media/MediaPlayer.html#StateDiagram

There’s another strange behavior where doing this frame-skip/save/render immediately after the movie starts produces a black rect. If the movie just plays normally though, no black rect appears. I wonder if this is a side-effect of MediaPlayer.seekTo()? Or maybe I’m just capturing a frame from the video before it has finished loading?

Is there any way to customize the color of the texture that is used by ofxAndroidVideoPlayer? If I could make it magenta to signify that it is rendering before any video contents have arrived that would be pretty helpful.