Это третья и последняя часть нашей публикации в Media с использованием серии Flex (см. Часть I и Часть II ). В первой статье мы показали, как создать приложение Twitter с помощью инфраструктуры Flex в Flash Builder, импортируя обложки Photoshop в Flash Catalyst для создания интерфейса и его взаимодействий. Во второй статье рассказывалось о процессах и библиотеках, необходимых для загрузки изображений в Flickr и использования API bit.ly для сокращения ссылок на эти изображения. В этой последней статье этой серии мы расширим приложение для загрузки видео на Flickr и будем использовать несколько встроенных функций Flex, чтобы получать скриншоты из видео и загружать их.
Как только вы закончите, не забудьте проверить свои знания в нашей статье викторины !
В предыдущей части мы обсудили потенциальные способы размещения изображений в Интернете для сопровождения твитов. Мы решили, что самым простым подходом было загрузить их на Flickr, создать свернутую ссылку на страницу Flickr с помощью API bit.ly, а затем включить эту ссылку в твит. Этот подход работал хорошо, поэтому мы сделаем то же самое для видео.
Прежде чем мы начнем, вы должны скачать архив кода, чтобы следовать вместе с. В этот раз мы будем работать с cheepcheep_video_flashbuilder.fxp
в папке Flex projects
(там также есть и предыдущие версии приложения, так что вы можете увидеть, что изменилось). Импортируйте этот файл в Flash Builder, и вы готовы начать работу.
Загрузка видео на Flickr
Наша первая задача — изменить фильтр, используемый элементом FileReference
для включения расширений видеофайлов, поддерживаемых Flickr. Мы добавили avi, wmv, mov, mpg, mp4, m4v и 3gp в FileFilter
который мы создали в предыдущей статье. Хотя все эти расширения официально поддерживаются Flickr, существует риск, что Flickr не сможет кодировать некоторые файлы; Это связано с тем, что видео может быть сжато различными кодеками, и поддерживаются только наиболее часто используемые (например, H.264). Мы рекомендуем вам проверить документацию Flickr на предмет того, что поддерживается.
Flickr позволяет загружать видео продолжительностью до 90 секунд и размером до 150 МБ для бесплатных учетных записей или до 500 МБ для учетных записей Pro. Понимая, что видеофайлы могут быть больше изображений, мы настроили оригинальный интерфейс, добавив дополнительный компонент Label
для отображения размера выбранного файла. Мы также добавили кнопку для просмотра параметров видео, если выбран видеофайл. Мы рассмотрим эту кнопку более подробно позже; сейчас просто обратите внимание, что по умолчанию он отключен.
Функция fileAccessed
, вызываемая после выбора файла, была изменена для получения дополнительной информации: размера файла (который мы отображаем с нашей новой Label
) и его расширения. FileReference
имеет свойство type, но оно ненадежно (например, оно не может определить расширение файла GIF), поэтому мы используем нашу собственную переменную. Чтобы получить расширение, мы разбиваем имя файла в каждом периоде и получаем последний элемент полученного массива. Мы также добавили массивы в верхней части основного приложения для хранения приемлемых расширений для фото и видео файлов:
private var photoExtensions:Array = ["gif","jpeg","jpg","png"]; private var videoExtensions:Array = ["avi","wmv","mov","mpg","mp4","m4v","3gp"]; ... private function fileAccessed(evt:Event):void { photoFileSize.text = (Number(fileReference.size)/100) + "kb"; photoFileName.text = fileReference.name; var filename:Array = fileReference.name.split("."); flickrUploadType = filename[filename.length - 1]; photoUploadBtn.enabled = true; }
Успешная загрузка в Flickr вызовет функцию uploadCompleteHandler
. Мы изменили эту функцию, чтобы назначить идентификатор загруженного носителя новой переменной flickrUploadID
. Мы также проверяем расширение файла, чтобы увидеть, находится ли он в массиве принятых расширений видео. Если это так, мы включаем новую кнопку Параметры видео . Остальная часть этой функции, которая захватывает URL-адрес загрузки с Flickr и передает ее нашему сервису bit.ly, не изменилась по сравнению с предыдущей статьей:
private function uploadCompleteHandler(evt:DataEvent):void { CursorManager.removeBusyCursor(); var xData:XML = new XML(evt.data); flickrUploadID = xData.photoid; if ( videoExtensions.indexOf(flickrUploadType) != -1 ) { videoOptionsBtn.enabled = true; } photoUrl = "http://www.flickr.com/photos/"+flickrNsid+"/"+xData.photoid; bitlyService.send(); }
Извлечение видео из Flickr
Мы собираемся использовать кнопку « Параметры видео» , чтобы перейти в новое состояние ( videoOptions
), которое мы добавили в приложение. Это состояние отображает новый компонент, который мы создали с помощью Flash Catalyst: его цель — отображать загруженное видео, чтобы пользователь мог также сделать снимок видео в качестве изображения для загрузки. Однако, прежде чем перейти в это состояние, нам нужно извлечь видео с Flickr для воспроизведения. Поэтому мы напишем одну функцию для отправки запроса в Flickr при нажатии кнопки, а другую — для переключения состояния приложения при получении ответа.
Первая функция, которую мы назвали showVideoOptions
, вызывает метод getSizes
API Flickr, используя ту же библиотеку Flickr ActionScript, которая использовалась в предыдущей статье. Он также устанавливает прослушиватель событий для обработки ответа API:
private function showVideoOptions():void { flickr = new FlickrService(flickrApiKey); flickr.addEventListener(FlickrResultEvent.PHOTOS_GET_SIZES, handleVideoData); flickr.photos.getSizes(flickrUploadID); }
Теперь давайте посмотрим на наш обратный вызов, функцию handleVideoData
. Если загрузка все еще обрабатывается Flickr, то FlickrResultEvent
, переданный этой функции, будет содержать ошибку, уведомляющую нас о том, что видео не было найдено. С другой стороны, если видео было обработано, результат будет содержать массив размеров фотографий. Одним из «размеров фотографий» на самом деле является видео MP4.
Наша первая задача — выяснить, нет ли в полученных данных ошибки. Мы можем сделать это с помощью встроенной функции hasOwnProperty
. Если мы обнаружим ошибку, мы отобразим Alert
для пользователя, чтобы сообщить ему, что видео все еще обрабатывается. В противном случае мы переключаемся в состояние videoOptions
чтобы отобразить новый компонент, а затем переходим по массиву photoSizes
ища значение «Site MP4» (которое является строкой «size», которую Flickr назначает для видео MP4). Затем мы передаем свойство source этого индекса массива в свойство videoLocation
нашего пользовательского компонента и вызываем метод setVideoPlayer
компонента:
private function handleVideoData(evt:FlickrResultEvent):void { if ( evt.data.hasOwnProperty("error") ) { Alert.show("It appears that Flickr is still processing your video, please wait another minute and try again", "Video not available"); } else { currentState = "videoOptions"; var len:Number = evt.data.photoSizes.length; for (var i:Number = 0;i<len;i++) { if ( evt.data.photoSizes[i].label == "Site MP4" ) { customcomponent31.videoLocation = evt.data.photoSizes[i].source; customcomponent31.setVideoPlayer(); break; } } } }
Отображение видео
CustomComponent3
имеет компонентVideoElement
расположенный в макете компонента с использованиемGroup
.VideoElement
- это новый компонент, представленный в Flex 4: это просто версия Chrome без компонентаVideoPlayer
. Это действительно удобно для захвата видеокадров, так как нет необходимости убирать управление плеером. ЭлементGroup
необходим по причинам, которые я объясню в ближайшее время.Функция
setVideoPlayer
, которую мы вызвали изhandleVideoData
, назначает URL-адрес видео свойствуVideoElement
компонентаVideoElement
. Это заставит компонент загрузить и воспроизвести видео. Мы также используем компонентProgressBar
, установленный вindeterminate
режим, чтобы дать пользователю визуальную подсказку о том, что файл загружается. Чтобы скрыть индикатор выполнения после завершения загрузки, нам нужно добавить новый прослушиватель событий в функциюinit
компонента. Слушатель вызывает функциюvideoLoadProgress
, которая скрывает индикатор выполнения и включает снимок:private function init():void { ... videoPlayer.addEventListener(ProgressEvent.PROGRESS,videoLoadProgress); ... } ... private function videoLoadProgress(evt:ProgressEvent):void { if ( evt.bytesLoaded == evt.bytesTotal || videoPlayer.playing ) { videoProgress.visible = false; snapshotBtn.enabled = true; } }
Нам нужен еще один обработчик событий, чтобы включить кнопку воспроизведения после завершения воспроизведения видео. Мы добавим еще одного слушателя в функцию
init
(используя событиеvideoElement.COMPLETE
) и создадим метод с именемenableReplayBtn
, который просто устанавливает значение свойстваenabled
кнопки вtrue
. Может показаться, что было бы проще просто добавить встроенный слушатель кvideoElement
, поскольку наша функцияenableReplayBtn
- это всего лишь одна строка кода. Тем не менее, в целях сохранения читабельности и удобства сопровождения нашего кода, имеет смысл размещать всех наших слушателей в одном месте.Снимки
Кнопка Snapshot вызывает функцию
frameGrab
, которую я перечислил ниже. Чтобы сделать снимок видео, мы используем функцию встроенного вспомогательного классаImageSnapshot
. Вместо того, чтобы фактически захватывать кадр непосредственно из видео,captureImage
просто возвращает текущее изображение, отображаемое элементом, на который вы указываете. Вот почему мы использовалиVideoElement
вместоVideoPlayer
: мы бы предпочли не брать элементы управления плеером вместе со скриншотом.Класс
ImageSnapshot
может бытьImageSnapshot
из любого компонента, который реализует классflash.display.IBitmapDrawable
. Это включает Flex UIComponents, но не включаетVideoPlayer
илиVideoElement
; Вот почему мы обернулиVideoElement
вGroup
.Мы присваиваем данные, захваченные функцией
captureImage
, переменной (чтобы мы могли получить к ней доступ позже из основного приложения), типизируя их какByteArray
используя ключевое словоas
. Затем мы назначаем эту переменную атрибуту источника нового компонентаImage
чтобы отобразить предварительный просмотр снимка. Наконец, мы включаем кнопку « Загрузить» :private function frameGrab(evt:Event):void { var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(videoGroup); snapshotPreview.source = imageSnap.data as ByteArray; uploadSnapshotBtn.enabled = true; }
С этим кодом пользователи могут просматривать видео, воспроизводить его так часто, как им нравится, и делать его снимки во время воспроизведения. Далее мы добавим функциональность, которая позволит им загружать текущий снимок на Flickr.
Загрузка ByteArray как изображения
Класс
Upload
используемой нами библиотеки Flickr был разработан для получения файла для загрузки из файловой системы пользователя. Для загрузки фотографий мы использовали элементFileReference
. Однако снимок, который мы записываем, является не файлом, а значением, которое существует в памяти и недоступно для элементаFileReference
. Итак, как мы можем загрузить его?Нет простого решения, но, к счастью для нас, другой человек столкнулся с этой проблемой и изменил класс
Upload
в библиотеке Flickr, чтобы добавить необходимые функции ( http://blog.dannypatterson.com/?p=250 ). Мы скопировали методuploadBytes
из этого сообщения в блоге и добавили его в файлUpload.as
(расположенный вcom.adobe.webapis.flickr.methodgroups
). Эта функция позволяет нам загружать нашByteArray
как если бы это было изображение. Нам нужно немного изменить функцию, добавив прослушиватель событий, который будет запущен после завершения загрузки. Этот слушатель вызывает другую новую функцию, которую мы также добавили вUpload.as
:uploadBytesComplete
. Мы используем его для отправки события, чтобы мы могли перехватить его в нашем приложении после завершения загрузки изображения:public function uploadBytes(...) : Boolean { ... loader.addEventListener(Event.COMPLETE, uploadBytesComplete); ... } private function uploadBytesComplete(event:Event):void { var result:FlickrResultEvent = new FlickrResultEvent(PHOTOS_UPLOAD_BYTES_COMPLETE ); MethodGroupHelper.processAndDispatch( _service, URLLoader( event.target.loader ).data, result,"photoid", MethodGroupHelper.parseUploadBytesResult ); }
Метод
uploadBytes
ведет себя почти так же, как и методupload
Flickr. Однако ему необходимо передать еще несколько параметров: заголовок изображения, описание, список тегов и флаг «public». Эти параметры также доступны дляupload
, но они являются необязательными, и мы опустили их для краткости.Чтобы использовать эту добавленную функциональность, мы написали новую функцию в нашем главном файле приложения:
uploadVideoCap
. Эта функция очень похожа наuploadFlickr
, за исключением того, что мы используемuploadBytes
вместоupload
. Вы заметите, что мы устанавливаемflickr.permission
для «записи». Это необходимо дляuploadBytes
функцииuploadBytes
:public function uploadVideoCap(capData:ByteArray):void { flickr = new FlickrService(flickrApiKey); flickr.secret = flickrSecret; flickr.token = flickrAuthToken; flickr.permission = "write"; flickr.addEventListener( FlickrResultEvent.PHOTOS_UPLOAD_BYTES_COMPLETE, videoCapUploaded ); var uploader:Upload = new Upload(flickr); uploader.uploadBytes(capData, "Video snapshot", "From Flex", "twitter,test,video,snapshot", true); CursorManager.setBusyCursor(); }
Когда скриншот будет загружен, мы вызываем функцию
videoCapUploaded
, которая просто захватывает URL-адрес Flickr и отправляет его в сервис bit.ly, который мы создали в предыдущей статье:private function videoCapUploaded(evt:FlickrResultEvent):void { CursorManager.removeBusyCursor(); photoUrl = "http://www.flickr.com/photos/"+flickrNsid+"/"+evt.data.photoid; bitlyService.send(); }
Вернувшись в наш пользовательский компонент, мы создали функцию
uploadSnapshot
для вызоваuploadVideoCap
.uploadSnapshot
привязывается к кнопке Upload с помощью прослушивателя событий в функцииinit
компонента. Чтобы вызвать функциюuploadVideoCap
из компонента, нам нужно указать его путь, используяmx.core.FlexGlobals.topLevelApplication
:
private function uploadSnapshot(evt:Event):void { mx.core.FlexGlobals.topLevelApplication.uploadVideoCap(imageByteArray); closeState(); }
Мы почти закончили! Теперь все, что нам нужно, это метод закрытия состояния
videoOptions
, чтобы убедиться, что мы остановили воспроизведение видео и вернули приложение в основное состояниеtwitterDisplay
. Сам методcloseState
довольноcloseState
. Обратите внимание, что он имеет необязательный параметрevt:Event
. Это потому, что мы также будем вызывать метод как обработчик события для кнопки закрытия компонента (в этом случае ему будет неявно передан параметрEvent
). Этот обработчик события объявлен в функцииinit
компонента:
private function init():void { ... closeBtn.addEventListener(MouseEvent.CLICK,closeState); ... } ... private function closeState(evt:Event = null):void { videoPlayer.stop(); mx.core.FlexGlobals.topLevelApplication.currentState = "twitterDisplay"; }
Вот и все! Это было интересное приложение, чтобы собрать. Хотя это, безусловно, функционально, есть множество функций, которые можно добавить для его округления: например, вы можете ограничить ввод текста в Твиттере до 140 символов или улучшить взаимодействие с моментальным снимком видео. Функциональность
ImageSnapshot
настолько проста, что ее легко представить в других видеоприложениях: например, добавление аннотаций для обратной связи оператору или редактору камеры.Надеемся, что эта серия покажет вам, как легко проектировать и создавать многофункциональные интернет-приложения с использованием Flash Catalyst и Flash Builder. Вы также должны понимать, как взаимодействовать с несколькими основными веб-API, которые очень пригодятся при разработке ваших собственных приложений для социальных сетей!
Чего же ты ждешь? Выходи и построй что-нибудь классное! Но прежде чем сделать это, почему бы вам не проверить то, что вы узнали, пройдя наш тест по статье ?