1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2012 The GemRB Project
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 *
19 */
20
21 #include "VLCPlayer.h"
22 #include "Video.h"
23
24 using namespace GemRB;
25
VLCPlayer(void)26 VLCPlayer::VLCPlayer(void)
27 {
28 libvlc = libvlc_new(0, NULL);
29 mediaPlayer = NULL;
30 planes[0] = NULL;
31 planes[1] = NULL;
32 planes[2] = NULL;
33 }
34
~VLCPlayer(void)35 VLCPlayer::~VLCPlayer(void)
36 {
37 DestroyPlayer();
38 libvlc_media_player_release(mediaPlayer);
39 libvlc_release(libvlc);
40 }
41
Open(DataStream * stream)42 bool VLCPlayer::Open(DataStream* stream)
43 {
44 DestroyPlayer();
45 if (stream) {
46 // we don't actually need anything from the stream. libVLC will open and use the file internally
47 libvlc_media_t* media = libvlc_media_new_path(libvlc, stream->originalfile);
48 mediaPlayer = libvlc_media_player_new_from_media(media);
49 libvlc_media_release(media); //player retains the media
50
51 libvlc_video_set_callbacks(mediaPlayer, lock, NULL, NULL, this);
52 libvlc_video_set_format_callbacks(mediaPlayer, setup, NULL);
53
54 bool success = libvlc_media_player_play(mediaPlayer) == 0;
55
56 // FIXME: this is technically a data race!
57 while (success && movieFormat == Video::BufferFormat::DISPLAY);
58
59 return success;
60 }
61 return false;
62 }
63
DecodeFrame(VideoBuffer & buf)64 bool VLCPlayer::DecodeFrame(VideoBuffer& buf)
65 {
66 int pitches[3];
67
68 switch (movieFormat) {
69 case Video::BufferFormat::RGB555:
70 pitches[0] = movieSize.w * 2;
71 break;
72 case Video::BufferFormat::YV12:
73 pitches[Y] = movieSize.w;
74 pitches[U] = movieSize.w / 2;
75 pitches[V] = movieSize.w / 2;
76 break;
77 default: // 32 bit
78 pitches[0] = movieSize.w * 4;
79 break;
80 }
81
82 buf.CopyPixels(Region(0, 0, movieSize.w, movieSize.h),
83 planes[0], &pitches[0], // Y or RGB
84 planes[1], &pitches[1], // U
85 planes[2], &pitches[2]);// V
86 return true;
87 }
88
DestroyPlayer()89 void VLCPlayer::DestroyPlayer()
90 {
91 if (mediaPlayer) {
92 libvlc_media_player_stop(mediaPlayer);
93 libvlc_media_player_release(mediaPlayer);
94 }
95
96 for (int i = 0; i < 3; ++i) {
97 delete[] planes[i];
98 }
99 }
100
101 // static vlc callbacks
102
lock(void * data,void ** planes)103 void* VLCPlayer::lock(void *data, void **planes)
104 {
105 VLCPlayer* player = static_cast<VLCPlayer*>(data);
106
107 planes[0] = player->planes[0];
108 planes[1] = player->planes[1];
109 planes[2] = player->planes[2];
110
111 return NULL; // we are using a single buffer so return NULL
112 }
113
setup(void ** opaque,char * chroma,unsigned * width,unsigned * height,unsigned * pitches,unsigned * lines)114 unsigned VLCPlayer::setup(void **opaque, char *chroma, unsigned *width, unsigned *height, unsigned *pitches, unsigned *lines)
115 {
116 VLCPlayer* player = static_cast<VLCPlayer*>(*opaque);
117 int w = *width;
118 int h = *height;
119 player->movieSize.w = w;
120 player->movieSize.h = h;
121
122 if (strcmp(chroma, "RV16") == 0) { // 16bit RGB
123 player->movieFormat = Video::BufferFormat::RGB555;
124
125 pitches[0] = w * 2;
126 lines[0] = h;
127
128 player->planes[0] = new char[pitches[0] * lines[0]];
129 } else if (strcmp(chroma, "YV12") == 0 || strcmp(chroma, "I420") == 0) {
130 player->movieFormat = Video::BufferFormat::YV12;
131 memcpy(chroma, "YV12", 4); // we prefer this plane order
132
133 pitches[Y] = w;
134 pitches[U] = w / 2;
135 pitches[V] = w / 2;
136 lines[Y] = h;
137 lines[U] = h / 2;
138 lines[V] = h / 2;
139
140 player->planes[Y] = new char[pitches[Y] * lines[Y]];
141 player->planes[U] = new char[pitches[U] * lines[U]];
142 player->planes[V] = new char[pitches[V] * lines[V]];
143 } else { // default to 32bit
144 player->movieFormat = Video::BufferFormat::RGBA8888;
145 memcpy(chroma, "RV32", 4);
146
147 pitches[0] = w * 4;
148 lines[0] = h;
149
150 player->planes[0] = new char[pitches[0] * lines[0]];
151 }
152
153 return 1; // indicates the number of buffers allocated
154 }
155
156 #include "plugindef.h"
157
158 GEMRB_PLUGIN(0x218963DD, "VLC Video Player")
159 // TODO: VLC is quite capable of playing various movie formats
160 // it seems silly to hardcode a single value or add formats piecemeal.
161 // it would be a shame to force modders or new content creators to use a specific format
162 PLUGIN_RESOURCE(VLCPlayer, "mov") // at least some mac ports used Quicktime MOV format
163 PLUGIN_RESOURCE(VLCPlayer, "webm") // EE movies
164 END_PLUGIN()
165