1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mediactrl_ffmpeg.cpp
3 // Purpose: Displays video
4 // Author: Alex Thuering
5 // Created: 21.01.2011
6 // RCS-ID: $Id: mediactrl_ffmpeg.cpp,v 1.12 2015/08/02 17:31:18 ntalex Exp $
7 // Copyright: (c) Alex Thuering
8 // Licence: GPL
9 /////////////////////////////////////////////////////////////////////////////
10
11 #include "mediactrl_ffmpeg.h"
12 #include <wx/wx.h>
13 #include <wx/dcclient.h>
14 #include <wxSVG/mediadec_ffmpeg.h>
15
16 using namespace std;
17
18 class FFEvtHandler: public wxEvtHandler {
19 public:
FFEvtHandler(wxMediaCtrl * ctrl)20 FFEvtHandler(wxMediaCtrl* ctrl): m_ctrl(ctrl) {
21 m_videoFormat = vfPAL;
22 m_aspectRatio = ar4_3;
23 m_frameAspectRatio = 1;
24 }
25
~FFEvtHandler()26 virtual ~FFEvtHandler() {
27 // nothing to do
28 }
29
GetImage()30 inline wxImage GetImage() {
31 return m_image;
32 }
33
SetImage(wxImage image)34 inline void SetImage(wxImage image) {
35 m_image = image;
36 m_bitmap = wxBitmap();
37 m_ctrl->Refresh();
38 }
39
SetFrameAspectRatio(float frameAspectRatio)40 inline void SetFrameAspectRatio(float frameAspectRatio) {
41 m_frameAspectRatio = frameAspectRatio;
42 }
43
SetVideoFormat(VideoFormat videoFormat,AspectRatio aspectRatio,const vector<int> & pad,const vector<int> & crop)44 inline void SetVideoFormat(VideoFormat videoFormat, AspectRatio aspectRatio,
45 const vector<int>& pad, const vector<int>& crop) {
46 m_videoFormat = videoFormat;
47 m_aspectRatio = aspectRatio;
48 m_pad = pad;
49 m_crop = crop;
50 m_bitmap = wxBitmap();
51 m_ctrl->Refresh();
52 }
53
54 protected:
OnPaint(wxPaintEvent & event)55 void OnPaint(wxPaintEvent &event) {
56 wxPaintDC dc(m_ctrl);
57 if (!m_bitmap.Ok()) {
58 if (!m_image.Ok())
59 return;
60 wxImage img = m_image;
61 double aspect = m_frameAspectRatio;
62 if (m_aspectRatio != arAUTO)
63 aspect = m_aspectRatio == ar4_3 ? 4.0/3 : 16.0/9;
64 wxSize frameSize = m_videoFormat != vfCOPY ? GetFrameSize(m_videoFormat)
65 : wxSize(img.GetWidth(), img.GetHeight());
66 if (m_crop.size() == 4 && m_crop[0] + m_crop[1] + m_crop[2] + m_crop[3] > 0) {
67 int w = img.GetWidth() - m_crop[0] - m_crop[1];
68 int h = img.GetHeight() - m_crop[2] - m_crop[3];
69 img = img.GetSubImage(wxRect(m_crop[0], m_crop[2], w > 0 ? w : 0, h > 0 ? h : 0));
70 }
71 wxSize size = m_ctrl->GetClientSize();
72 m_dspSize = size;
73 m_dspPos = wxPoint();
74 if (size.y >= size.x/aspect) {
75 m_dspSize.y = size.x/aspect;
76 m_dspPos.y = (size.y - m_dspSize.y)/2;
77 } else {
78 m_dspSize.x = size.y*aspect;
79 m_dspPos.x = (size.x - m_dspSize.x)/2;
80 }
81 wxSize bmpSize = m_dspSize;
82 m_bmpPos = m_dspPos;
83 if (m_pad.size() == 4 && m_pad[0] + m_pad[1] + m_pad[2] + m_pad[3] > 0) {
84 int padX = m_pad[0] + m_pad[1];
85 int padY = m_pad[2] + m_pad[3];
86 bmpSize.x -= padX*m_dspSize.x/frameSize.x;
87 bmpSize.y -= padY*m_dspSize.y/frameSize.y;
88 m_bmpPos.x += m_pad[0]*m_dspSize.x/frameSize.x;
89 m_bmpPos.y += m_pad[2]*m_dspSize.y/frameSize.y;
90 }
91 m_bitmap = wxBitmap(img.Scale(bmpSize.x, bmpSize.y));
92 }
93 dc.SetPen(*wxTRANSPARENT_PEN);
94 dc.SetBrush(*wxBLACK_BRUSH);
95 dc.DrawRectangle(m_dspPos, m_dspSize);
96 dc.DrawBitmap(m_bitmap, m_bmpPos);
97 }
98
OnResize(wxSizeEvent & event)99 void OnResize(wxSizeEvent &event) {
100 m_bitmap = wxBitmap();
101 m_ctrl->Refresh();
102 }
103
104 private:
105 wxMediaCtrl* m_ctrl;
106 wxImage m_image;
107 float m_frameAspectRatio;
108 VideoFormat m_videoFormat;
109 AspectRatio m_aspectRatio;
110 vector<int> m_pad;
111 vector<int> m_crop;
112 wxSize m_dspSize;
113 wxPoint m_dspPos;
114 wxBitmap m_bitmap;
115 wxPoint m_bmpPos;
116 DECLARE_EVENT_TABLE()
117 };
118
119 BEGIN_EVENT_TABLE(FFEvtHandler, wxEvtHandler)
120 EVT_PAINT(FFEvtHandler::OnPaint)
121 EVT_SIZE(FFEvtHandler::OnResize)
122 END_EVENT_TABLE()
123
124 /////////////////////////////////////////////////////////////////////////////
125 /////////////////////////// wxFFMediaBackend ////////////////////////////////
126 /////////////////////////////////////////////////////////////////////////////
127 class wxFFMediaBackend: public wxMediaBackendCommonBase {
128 public:
wxFFMediaBackend()129 wxFFMediaBackend(): m_loaded(false), m_duration(0), m_evtHandler(NULL) {}
~wxFFMediaBackend()130 virtual ~wxFFMediaBackend() {
131 if (m_evtHandler != NULL) {
132 m_ctrl->PopEventHandler(true);
133 m_evtHandler = NULL;
134 }
135 }
136
CreateControl(wxControl * ctrl,wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)137 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent, wxWindowID id, const wxPoint& pos,
138 const wxSize& size, long style, const wxValidator& validator, const wxString& name) {
139 if (!ctrl->wxControl::Create(parent, id, pos, size, style, validator, name))
140 return false;
141 m_ctrl = wxStaticCast(ctrl, wxMediaCtrl);
142 m_evtHandler = new FFEvtHandler(m_ctrl);
143 m_ctrl->PushEventHandler(m_evtHandler);
144 return true;
145 }
146
Load(const wxString & fileName)147 virtual bool Load(const wxString& fileName) {
148 if (fileName.length() && m_decoder.Load(fileName)) {
149 m_loaded = true;
150 m_duration = m_decoder.GetDuration();
151 if (m_duration < 0) {
152 if (m_decoder.SetPosition(360000, false))
153 m_duration = m_decoder.GetPosition();
154 m_decoder.SetPosition(0, false);
155 }
156 NotifyMovieLoaded();
157 m_evtHandler->SetImage(m_decoder.GetNextFrame());
158 m_evtHandler->SetFrameAspectRatio(m_decoder.GetFrameAspectRatio());
159 return true;
160 }
161 m_loaded = false;
162 m_evtHandler->SetImage(wxImage());
163 return false;
164 }
165
SetPosition(wxLongLong where)166 virtual bool SetPosition(wxLongLong where) {
167 if (!m_loaded)
168 return false;
169 double dpos = where.ToDouble()/1000;
170 if (dpos == 0 && m_decoder.GetPosition() != 0) {
171 m_decoder.SetPosition(0, false);
172 for (int i = 0; i < 8; i++) {
173 m_decoder.GetNextFrame();
174 }
175 }
176 m_decoder.SetPosition(dpos > 1.0 ? dpos - 1.0 : 0.0, dpos != 0);
177 wxImage image;
178 for (int i = 0; i < 60; i++) {
179 image = m_decoder.GetNextFrame();
180 if (m_decoder.GetPosition() >= dpos)
181 break;
182 }
183 m_evtHandler->SetImage(image);
184 return true;
185 }
186
GetPosition()187 virtual wxLongLong GetPosition() {
188 wxLongLong res;
189 if (m_loaded)
190 res.Assign(m_decoder.GetPosition()*1000);
191 return res;
192 }
193
GetDuration()194 virtual wxLongLong GetDuration() {
195 wxLongLong res;
196 if (m_loaded)
197 res.Assign(m_duration*1000);
198 return res;
199 }
200
SetVideoFormat(VideoFormat videoFormat,AspectRatio aspectRatio,const vector<int> & pad,const vector<int> & crop)201 void SetVideoFormat(VideoFormat videoFormat, AspectRatio aspectRatio, const vector<int>& pad, const vector<int>& crop) {
202 m_evtHandler->SetVideoFormat(videoFormat, aspectRatio, pad, crop);
203 }
204
GetFps()205 inline double GetFps() {
206 return m_decoder.GetFps();
207 }
208
GetDecoder()209 inline wxFfmpegMediaDecoder& GetDecoder() {
210 return m_decoder;
211 }
212
GetImage()213 inline wxImage GetImage() {
214 return m_evtHandler->GetImage();
215 }
216
217 private:
218 bool m_loaded;
219 wxFfmpegMediaDecoder m_decoder;
220 double m_duration;
221 FFEvtHandler* m_evtHandler;
222 DECLARE_DYNAMIC_CLASS(wxFFMediaBackend)
223 };
224
IMPLEMENT_DYNAMIC_CLASS(wxFFMediaBackend,wxMediaBackend)225 IMPLEMENT_DYNAMIC_CLASS(wxFFMediaBackend, wxMediaBackend)
226
227 /////////////////////////////////////////////////////////////////////////////
228 ////////////////////////////// MediaCtrlFF //////////////////////////////////
229 /////////////////////////////////////////////////////////////////////////////
230 MediaCtrlFF::MediaCtrlFF(wxWindow* parent, wxWindowID id, const wxString& fileName, const wxPoint& pos,
231 const wxSize& size, long style, const wxValidator& validator, const wxString& name):
232 wxMediaCtrl(parent, id, fileName, pos, size, style, wxT("wxFFMediaBackend"), validator, name) {
233 // nothing to do
234 if (m_imp == NULL) {
235 m_imp = new wxFFMediaBackend();
236 if (!m_imp->CreateControl(this, parent, id, pos, size, style, validator, name)) {
237 delete m_imp;
238 m_imp = NULL;
239 }
240 }
241 }
242
~MediaCtrlFF()243 MediaCtrlFF::~MediaCtrlFF() {
244 // nothing to do
245 }
246
SetVideoFormat(VideoFormat videoFormat,AspectRatio aspectRatio,const vector<int> & pad,const vector<int> & crop)247 void MediaCtrlFF::SetVideoFormat(VideoFormat videoFormat, AspectRatio aspectRatio,
248 const vector<int>& pad, const vector<int>& crop) {
249 ((wxFFMediaBackend*) m_imp)->SetVideoFormat(videoFormat, aspectRatio, pad, crop);
250 }
251
GetFps()252 double MediaCtrlFF::GetFps() {
253 return ((wxFFMediaBackend*) m_imp)->GetFps();
254 }
255
GetDecoder()256 wxFfmpegMediaDecoder& MediaCtrlFF::GetDecoder() {
257 return ((wxFFMediaBackend*) m_imp)->GetDecoder();
258 }
259
GetImage()260 wxImage MediaCtrlFF::GetImage() {
261 return ((wxFFMediaBackend*) m_imp)->GetImage();
262 }
263