1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13:
14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26: class IMP_Mime_Viewer_Video extends Horde_Mime_Viewer_Default
27: {
28: 29: 30: 31: 32:
33: protected $_capability = array(
34: 'full' => false,
35: 'info' => true,
36: 'inline' => true,
37: 'raw' => false
38: );
39:
40: 41: 42: 43: 44: 45: 46: 47: 48:
49: protected function _render()
50: {
51: switch ($GLOBALS['injector']->getInstance('Horde_Variables')->imp_video_view) {
52: case 'view_thumbnail':
53:
54: return $this->_thumbnail();
55:
56: default:
57: return parent::_render();
58: }
59: }
60:
61: 62: 63: 64: 65:
66: protected function _renderInfo()
67: {
68: global $registry;
69:
70: if ($registry->getView() == $registry::VIEW_MINIMAL) {
71: return array();
72: }
73:
74: $status = array();
75:
76: $mime_id = $this->_mimepart->getMimeId();
77: $headers = Horde_Mime_Headers::parseHeaders($this->getConfigParam('imp_contents')->getBodyPart($mime_id, array(
78: 'length' => 0,
79: 'mimeheaders' => true,
80: 'stream' => true
81: ))->data);
82:
83: if (($duration = $headers->getValue('content-duration')) !== null) {
84: $text = array();
85:
86: if ($minutes = floor($duration / 60)) {
87: $text[] = sprintf(
88: ngettext(_("%d minute"), _("%d minutes"), $minutes),
89: $minutes
90: );
91: }
92:
93: if ($seconds = ($duration % 60)) {
94: $text[] = sprintf(
95: ngettext(_("%d second"), _("%d seconds"), $seconds),
96: $seconds
97: );
98: }
99:
100: $status[] = sprintf(_("This video file is reported to be %s in length."), implode(' ', $text));
101: }
102:
103: if ($this->_thumbnailBinary()) {
104: $status[] = _("This is a thumbnail of a video attachment.");
105: $status[] = $this->getConfigParam('imp_contents')->linkViewJS(
106: $this->_mimepart,
107: 'view_attach',
108: '<img src="' . $this->getConfigParam('imp_contents')->urlView($this->_mimepart, 'view_attach', array('params' => array('imp_video_view' => 'view_thumbnail'))) . '" />',
109: null,
110: null,
111: null
112: );
113: }
114:
115: if (empty($status)) {
116: return array();
117: }
118:
119: $s = new IMP_Mime_Status($status);
120: $s->icon('mime/video.png');
121:
122: return array(
123: $this->_mimepart->getMimeId() => array(
124: 'data' => '',
125: 'status' => $s,
126: 'type' => 'text/html; charset=UTF-8'
127: )
128: );
129: }
130:
131: 132: 133: 134: 135:
136: protected function _thumbnail()
137: {
138: if (!($ffmpeg = $this->_thumbnailBinary())) {
139: return array();
140: }
141:
142: $process = proc_open(
143: escapeshellcmd($ffmpeg) . ' -i pipe:0 -vframes 1 -an -ss 1 -s 240x180 -f mjpeg pipe:1',
144: array(
145: 0 => array('pipe', 'r'),
146: 1 => array('pipe', 'w')
147: ),
148: $pipes
149: );
150:
151: $out = null;
152: if (is_resource($process)) {
153: fwrite($pipes[0], $this->_mimepart->getContents());
154: fclose($pipes[0]);
155:
156: $out = stream_get_contents($pipes[1]);
157: fclose($pipes[1]);
158: }
159:
160: if (strlen($out)) {
161: $type = 'image/jpeg';
162: } else {
163: $type = 'image/png';
164: $img_ob = Horde_Themes::img('mini-error.png', 'imp');
165: $out = file_get_contents($img_ob->fs);
166: }
167:
168: return array(
169: $this->_mimepart->getMimeId() => array(
170: 'data' => $out,
171: 'type' => 'image/jpeg'
172: )
173: );
174: }
175:
176: 177: 178: 179: 180:
181: protected function _thumbnailBinary()
182: {
183: return ($this->getConfigParam('thumbnails') &&
184: ($ffmpeg = $this->getConfigParam('ffmpeg')) &&
185: is_executable($ffmpeg))
186: ? $ffmpeg
187: : false;
188: }
189:
190: }
191: