使用Flex在Twitter上共享媒体,第三部分:视频

tech2023-12-16  30

This is the third and final part in our Share Media on Twitter Using Flex series (read Part I and Part II). In the first article we showed you how to build a Twitter application with the Flex framework in Flash Builder, importing Photoshop artwork into Flash Catalyst to build both the interface and its interactions. The second article took you through the processes and libraries needed to upload images to Flickr and use the bit.ly API to shorten the links to those images. With this final article in the series we’ll extend the application to upload video to Flickr, and use a few built-in Flex features to grab screenshots from the video and upload them as well.

这是我们在Twitter上使用Flex系列共享媒体的第三部分,也是最后一部分(请阅读第一部分和第二部分 )。 在第一篇文章中,我们向您展示了如何使用Flash Builder中的Flex框架构建Twitter应用程序,如何将Photoshop图稿导入Flash Catalyst中以构建界面及其交互。 第二篇文章介绍了将图像上传到Flickr并使用bit.ly API缩短到这些图像的链接所需的过程和库。 在本系列的最后一篇文章中,我们将扩展应用程序以将视频上传到Flickr,并使用一些内置的Flex功能从视频中截取屏幕截图并上传它们。

Once you’re done, be sure to test your knowledge in our Article Quiz!

完成后,请务必在我们的文章测验中测试您的知识!

In the previous installment we discussed potential ways of hosting images online to accompany a Tweet. We decided the simplest approach was to upload them to Flickr, create a minimized link to the Flickr page using the bit.ly API, and then include that link in a tweet. That approach worked well, so we’ll do the same for video.

在上一部分中,我们讨论了在线托管图像以伴随Tweet的潜在方法。 我们认为最简单的方法是将它们上传到Flickr,使用bit.ly API创建到Flickr页面的最小链接,然后将该链接包含在推文中。 这种方法效果很好,因此我们将对视频执行相同的操作。

Before we start, you should download the code archive to follow along with. The file we’ll be working with this time around is cheepcheep_video_flashbuilder.fxp, in the Flex projects folder (the previous versions of the application are there as well, so you can see what’s changed). Import that file into Flash Builder, and you’re ready to get started.

在我们开始之前,您应该下载代码归档以进行后续操作。 这次我们要使用的文件是cheepcheep_video_flashbuilder.fxp ,位于Flex projects文件夹中(该应用程序的先前版本也存在,因此您可以看到更改了)。 将该文件导入Flash Builder,就可以开始了。

将视频上传到Flickr (Uploading Video to Flickr)

Our first task is to modify the filter used by the FileReference element to include the video file extensions supported by Flickr. We’ve added avi, wmv, mov, mpg, mp4, m4v, and 3gp to the FileFilter that we created in the last article. Although these extensions are all officially supported by Flickr, there is still a risk that Flickr will be unable to encode some files; this is because video can be compressed with a variety of different codecs and only the most commonly used (like H.264) are supported. We recommend that you check the Flickr documentation for what’s supported.

我们的第一个任务是修改FileReference元素使用的过滤器,以包括Flickr支持的视频文件扩展名。 我们已经在上一篇文章中创建的FileFilter中添加了avi,wmv,mov,mpg,mp4,m4v和3gp。 尽管Flickr正式支持了这些扩展名,但仍有Flickr无法编码某些文件的风险。 这是因为可以使用各种不同的编解码器压缩视频,并且仅支持最常用的编解码器(例如H.264)。 我们建议您检查Flickr文档以了解受支持的内容。

Flickr allows you to upload video of up to 90 seconds in duration and 150MB in size for free accounts, or up to 500MB for Pro accounts. Realizing that video files can be larger than images, we’ve tweaked the original interface, adding an extra Label component to display the size of the selected file. We’ve also added a button to view video options if a video file is selected. We’ll look at this button in more detail later; for now just notice that it’s disabled by default.

Flickr允许您上传长达90秒的视频,免费帐户上传150MB的视频,而Pro帐户上传高达500MB的视频。 考虑到视频文件可能比图像大,我们对原始界面进行了调整,添加了一个额外的Label组件以显示所选文件的大小。 如果选择了视频文件,我们还添加了一个按钮来查看视频选项。 稍后,我们将更详细地介绍该按钮。 现在只需注意默认情况下它处于禁用状态。

The fileAccessed function, called once a file has been selected, has been modified to pull in extra information: the size of the file (which we display with our new Label), and its extension. FileReference does have a type property, but it’s unreliable (for example, it’s unable to determine the extension of a GIF file), so we’re using our own variable. To obtain the extension, we split the filename at each period and grab the last element of the resulting array. We’ve also added arrays at the top of the main application to store the acceptable extensions for both photo and video files:

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; }

A successful upload to Flickr will call the uploadCompleteHandler function. We’ve modified that function to assign the uploaded media’s ID to a new flickrUploadID variable. We also test the extension of the file to see if it’s in the array of accepted video extensions. If it is, we enable the new Video Options button. The rest of this function, which grabs the URL of the upload from Flickr and submits it to our bit.ly service, is unchanged from the last article:

成功上传到Flickr将会调用uploadCompleteHandler函数。 我们已经修改了该函数,以将上载的媒体ID分配给新的flickrUploadID变量。 我们还测试了文件的扩展名,以查看它是否在可接受的视频扩展名数组中。 如果是这样,我们启用新的“ 视频选项”按钮。 该功能的其余部分(从Flickr抓取上传的URL并将其提交给我们的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获取视频 (Fetching the Video from Flickr)

We’re going to use the Video Options button to switch to a new state (videoOptions) that we’ve added to the application. This state displays a new component that we created with Flash Catalyst: its purpose is to display the uploaded video to enable the user to grab a snapshot of the video as an image for uploading as well. Before switching to this state, however, we need to retrieve the video from Flickr for playback. So we’ll write one function to send a request to Flickr when the button is clicked, and another to switch the application’s state when a response is received.

我们将使用“ 视频选项”按钮切换到已添加到应用程序的新状态( videoOptions )。 此状态显示了我们使用Flash Catalyst创建的新组件:其目的是显示上传的视频,以使用户也可以将视频的快照作为要上传的图像。 但是,在切换到此状态之前,我们需要从Flickr检索视频以进行播放。 因此,我们将编写一个函数,以在单击按钮时向Flickr发送请求,而另一个函数则在收到响应时切换应用程序的状态。

The first function, which we’ve called showVideoOptions, calls the getSizes method of the Flickr API using the same Flickr ActionScript library employed in the last article. It also sets an event listener to handle the API response:

第一个函数称为showVideoOptions ,它使用上一篇文章中使用的相同Flickr ActionScript库调用Flickr API的getSizes方法。 它还设置了一个事件侦听器来处理API响应:

private function showVideoOptions():void {  flickr = new FlickrService(flickrApiKey);    flickr.addEventListener(FlickrResultEvent.PHOTOS_GET_SIZES, handleVideoData);    flickr.photos.getSizes(flickrUploadID);  }

Now let’s take a look at our callback, the handleVideoData function. If the upload is still being processed by Flickr, the FlickrResultEvent that gets passed to this function will contain an error to notify us that the video hasn’t been found. On the other hand, if the video has been processed, the result will contain an array of photo sizes. One of the “photo sizes” is actually the MP4 video.

现在让我们看一下我们的回调handleVideoData函数。 如果Flickr仍在处理上载,则传递给此函数的FlickrResultEvent将包含错误,以通知我们未找到视频。 另一方面,如果视频已经过处理,则结果将包含一组照片尺寸。 “照片大小”之一实际上是MP4视频。

Our first task then is to see if the data received contains an error. We can do this using the built-in function hasOwnProperty. If we find an error, we display an Alert to the user to inform them that the video is still processing. Otherwise, we switch to the videoOptions state to display the new component, then loop over the photoSizes array looking for a value of “Site MP4” (which is the “size” string that Flickr assigns to MP4 video). We then pass the source property of that array index to our custom component’s videoLocation property, and call the component’s setVideoPlayer method:

然后,我们的第一个任务是查看接收到的数据是否包含错误。 我们可以使用内置函数hasOwnProperty做到这一点。 如果发现错误,则会向用户显示Alert ,以通知他们视频仍在处理中。 否则,我们将切换到videoOptions状态以显示新组件,然后在photoSizes数组上循环查找“ Site MP4”值(这是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;        }      }    }  }

显示视频 (Displaying the Video)

CustomComponent3 has a VideoElement component positioned in the component's layout using a Group. VideoElement is a new component introduced with Flex 4: it's basically just a chrome-less version of the VideoPlayer component. It's really handy for grabbing video frames, as there's no need to strip away the player controls. The Group element is necessary for reasons I'll explain shortly.

The setVideoPlayer function, which we called from handleVideoData, assigns the video's URL to the source property of the VideoElement component. This will make the component download and play the video. We're also using a ProgressBar component, set to indeterminate mode, to give the user a visual cue that the file is being downloaded. To hide the progress bar once the download is complete, we need to add a new event listener to the component's init function. The listener calls the videoLoadProgress function, which hides the progress bar and enables the snapshot:

We need one more event handler, to enable the Replay button once the video is done playing. We'll add another listener to the init function (using the videoElement.COMPLETE event) and create a method called enableReplayBtn, which simply sets the value of the button's enabled property to true. It might seem like it would be easier just to add an inline listener to the videoElement itself, since our enableReplayBtn function is only one line of code. However, in the interest of keeping our code readable and maintainable, it makes more sense to have all our listeners in the same place.

Taking Snapshots

The Snapshot button calls the frameGrab function, which I've listed below. In order to take a snapshot of the video, we're using a function of Flex's built-in ImageSnapshot helper class. Rather than actually grabbing a frame directly from the video, captureImage just returns the current image displayed by the element you point it at. This is why we used VideoElement instead of VideoPlayer: we'd prefer to avoid grabbing the player controls along with the screenshot.

The ImageSnapshot class can capture from any component that implements the flash.display.IBitmapDrawable class. This includes Flex UIComponents, but doesn't include VideoPlayer or VideoElement; this is why we wrapped the VideoElement in a Group.

We assign the data grabbed by the captureImage function to a variable (so we can access it later from the main application), typecasting it as a ByteArray using the as keyword. Then we assign that variable to the source attribute of a new Image component to display a preview of the snapshot. Finally, we enable the Upload button:

private function frameGrab(evt:Event):void {  var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(videoGroup);    snapshotPreview.source = imageSnap.data as ByteArray;    uploadSnapshotBtn.enabled = true;  }

With this code in place, users can view the video, replay it as often as they like, and take snapshots of it while it's playing. Next, we'll add functionality to allow them to upload the current snapshot to Flickr.

Uploading a ByteArray as Image

The Upload class of the Flickr library that we're using was designed to receive a file for upload from the user's file system. For our photo uploads, we've used the FileReference element to do this. However, rather than being a file, the snapshot that we're capturing is a value that exists in memory and is inaccessible to the FileReference element. So how do we upload it?

There's no easy solution, but fortunately for us another person has encountered this issue and has modified the Upload class in the Flickr library to add the required functionality (http://blog.dannypatterson.com/?p=250). We've copied the uploadBytes method from that blog post and added it to the Upload.as file (located in com.adobe.webapis.flickr.methodgroups). This function allows us to upload our ByteArray as if it were an image. We need to modify the function slightly, adding an event listener to fire when the upload is complete. This listener calls another new function that we've also added to Upload.as: uploadBytesComplete. We use it to dispatch the event so that we can catch it within our application once the image has finished uploading:

The uploadBytes method behaves in almost exactly the same way as the Flickr upload method. However, a few more parameters need to be passed to it: an image title, a description, a list of tags, and a "public" flag. These parameters are also available to upload, but they're optional and we omitted them for the sake of brevity.

To make use of this added functionality, we've written a new function in our main application file: uploadVideoCap. This function is very similar to uploadFlickr, except that we're using uploadBytes instead of upload. You'll notice that we're setting flickr.permission to "write." This is required for the uploadBytes function to work correctly:

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();           }

When the screenshot is done uploading we call the videoCapUploaded function, which just grabs the Flickr URL and submits it to the bit.ly service we created in the last article:

Back in our custom component, we've created a function called uploadSnapshot to call uploadVideoCap. uploadSnapshot is then bound to the Upload button with an event listener in the component's init function. To call the uploadVideoCap function from inside the component, we need to specify its path using mx.core.FlexGlobals.topLevelApplication:   private function uploadSnapshot(evt:Event):void {    mx.core.FlexGlobals.topLevelApplication.uploadVideoCap(imageByteArray);    closeState();   }

We’re almost done! Now all we need is a method to close the videoOptions state, to make sure we stop the video playback and switch the application back to the main twitterDisplay state. The closeState method itself is fairly self-explanatory. Notice that it has an optional evt:Event parameter. This is because we’ll also be calling the method as an event handler for the component’s close button (in which case it will implicitly be passed an Event parameter). This event handler is declared in the component’s init function:

private function init():void {    ...    closeBtn.addEventListener(MouseEvent.CLICK,closeState);    ...   }     ...     private function closeState(evt:Event = null):void {    videoPlayer.stop();    mx.core.FlexGlobals.topLevelApplication.currentState = "twitterDisplay";       }  

And that’s it! This has been an interesting application to put together. While it’s certainly functional, there are a lot of features that could be added to round it off: for example, you could limit the Twitter text input to 140 characters, or refine the video snapshot interaction. The ImageSnapshot functionality is so simple that it’s easy to imagine using it in other video applications: adding annotations for feedback to the camera operator or editor, for example.

Hopefully this series has shown you how easy it is to design and build a rich Internet application using Flash Catalyst and Flash Builder. You should also have a feel for how to interact with a few major web APIs, which will come in very handy in developing your own social media applications!

So what are you waiting for? Get out there and build something cool! But before you do, why don’t you test what you’ve learned by taking our Article Quiz?

CustomComponent3 has a VideoElement component positioned in the component's layout using a Group . VideoElement is a new component introduced with Flex 4: it's basically just a chrome-less version of the VideoPlayer component. It's really handy for grabbing video frames, as there's no need to strip away the player controls. The Group element is necessary for reasons I'll explain shortly.

The setVideoPlayer function, which we called from handleVideoData , assigns the video's URL to the source property of the VideoElement component. This will make the component download and play the video. We're also using a ProgressBar component, set to indeterminate mode, to give the user a visual cue that the file is being downloaded. To hide the progress bar once the download is complete, we need to add a new event listener to the component's init function. The listener calls the videoLoadProgress function, which hides the progress bar and enables the snapshot:

We need one more event handler, to enable the Replay button once the video is done playing. We'll add another listener to the init function (using the videoElement.COMPLETE event) and create a method called enableReplayBtn , which simply sets the value of the button's enabled property to true . It might seem like it would be easier just to add an inline listener to the videoElement itself, since our enableReplayBtn function is only one line of code. However, in the interest of keeping our code readable and maintainable, it makes more sense to have all our listeners in the same place.

Taking Snapshots

The Snapshot button calls the frameGrab function, which I've listed below. In order to take a snapshot of the video, we're using a function of Flex's built-in ImageSnapshot helper class. Rather than actually grabbing a frame directly from the video, captureImage just returns the current image displayed by the element you point it at. This is why we used VideoElement instead of VideoPlayer : we'd prefer to avoid grabbing the player controls along with the screenshot.

The ImageSnapshot class can capture from any component that implements the flash.display.IBitmapDrawable class. This includes Flex UIComponents, but doesn't include VideoPlayer or VideoElement ; this is why we wrapped the VideoElement in a Group .

We assign the data grabbed by the captureImage function to a variable (so we can access it later from the main application), typecasting it as a ByteArray using the as keyword. Then we assign that variable to the source attribute of a new Image component to display a preview of the snapshot. Finally, we enable the Upload button:

private function frameGrab(evt:Event):void {  var imageSnap:ImageSnapshot = ImageSnapshot.captureImage(videoGroup);    snapshotPreview.source = imageSnap.data as ByteArray;    uploadSnapshotBtn.enabled = true;  }

With this code in place, users can view the video, replay it as often as they like, and take snapshots of it while it's playing. Next, we'll add functionality to allow them to upload the current snapshot to Flickr.

Uploading a ByteArray as Image

The Upload class of the Flickr library that we're using was designed to receive a file for upload from the user's file system. For our photo uploads, we've used the FileReference element to do this. However, rather than being a file, the snapshot that we're capturing is a value that exists in memory and is inaccessible to the FileReference element. So how do we upload it?

There's no easy solution, but fortunately for us another person has encountered this issue and has modified the Upload class in the Flickr library to add the required functionality ( http://blog.dannypatterson.com/?p=250 ). We've copied the uploadBytes method from that blog post and added it to the Upload.as file (located in com.adobe.webapis.flickr.methodgroups ). This function allows us to upload our ByteArray as if it were an image. We need to modify the function slightly, adding an event listener to fire when the upload is complete. This listener calls another new function that we've also added to Upload.as : uploadBytesComplete . We use it to dispatch the event so that we can catch it within our application once the image has finished uploading:

The uploadBytes method behaves in almost exactly the same way as the Flickr upload method. However, a few more parameters need to be passed to it: an image title, a description, a list of tags, and a "public" flag. These parameters are also available to upload , but they're optional and we omitted them for the sake of brevity.

To make use of this added functionality, we've written a new function in our main application file: uploadVideoCap . This function is very similar to uploadFlickr , except that we're using uploadBytes instead of upload . You'll notice that we're setting flickr.permission to "write." This is required for the uploadBytes function to work correctly:

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();           }

When the screenshot is done uploading we call the videoCapUploaded function, which just grabs the Flickr URL and submits it to the bit.ly service we created in the last article:

Back in our custom component, we've created a function called uploadSnapshot to call uploadVideoCap . uploadSnapshot is then bound to the Upload button with an event listener in the component's init function. To call the uploadVideoCap function from inside the component, we need to specify its path using mx.core.FlexGlobals.topLevelApplication :   private function uploadSnapshot(evt:Event):void {    mx.core.FlexGlobals.topLevelApplication.uploadVideoCap(imageByteArray);    closeState();   }

We’re almost done! Now all we need is a method to close the videoOptions state, to make sure we stop the video playback and switch the application back to the main twitterDisplay state. The closeState method itself is fairly self-explanatory. Notice that it has an optional evt:Event parameter. This is because we’ll also be calling the method as an event handler for the component’s close button (in which case it will implicitly be passed an Event parameter). This event handler is declared in the component’s init function:

private function init():void {    ...    closeBtn.addEventListener(MouseEvent.CLICK,closeState);    ...   }     ...     private function closeState(evt:Event = null):void {    videoPlayer.stop();    mx.core.FlexGlobals.topLevelApplication.currentState = "twitterDisplay";       }  

And that’s it! This has been an interesting application to put together. While it’s certainly functional, there are a lot of features that could be added to round it off: for example, you could limit the Twitter text input to 140 characters, or refine the video snapshot interaction. The ImageSnapshot functionality is so simple that it’s easy to imagine using it in other video applications: adding annotations for feedback to the camera operator or editor, for example.

Hopefully this series has shown you how easy it is to design and build a rich Internet application using Flash Catalyst and Flash Builder. You should also have a feel for how to interact with a few major web APIs, which will come in very handy in developing your own social media applications!

So what are you waiting for? Get out there and build something cool! But before you do, why don’t you test what you’ve learned by taking our Article Quiz ?

翻译自: https://www.sitepoint.com/share-media-flex-twitter-video/

相关资源:jdk-8u281-windows-x64.exe
最新回复(0)