How VideoCamera/PhotoCamera content is saved on Windows Phone 7
Last Friday I posted an article about how it is possible to use the "raw" video camera and camera stream in the application. Today I am explaining where exactly the data is stored when the user captures media content.
A PhotoCamera instance is only able to capture static images (one frame per capture). This is done via the CaptureImage method. So, for example:
PhotoCamera pCam = new PhotoCamera(CameraSource.PrimaryCamera);
Here, mainVisualizer is an instance of CameraVisualizer that will display the image stream live in the application. From here on the entire process becomes a bit tricky. First of all, the picture capture should occur once the camera is initialized. Therefore, the above code snippet should be placed somewhere where the camera will be initialized automatically, for example in the page constructor. The CaptureImage call can be put in a Click event handler for a button.
Once done, what happens when CaptureImage is called? Believe it or not, the image is stored in the isolated storage. But how exactly do I know what's the name of the file, so I can track it down internally? By default, there is no way I can specify it, but Reflector is coming to the rescue here.
Once I disassembled the CaptureImage method, I saw this:
imagePath and thumbnailPath are the two fields that interest me. It is clear where the data is saved considering that there is base.IsolatedStorageRoot present in the path combination method. However, the GetCurrentPhotoName and GetCurrentThumbnailName are behind the curtain.
Disassembling further, it is clear that the names are in fact GUIDs:
So the difference between the image path and the thumbnail path is _tn part in the name. The name itself can be obtained by using the ImageSavedToDisk event handler:
pCam.ImageSavedToDisk += new EventHandler<ContentReadyEventArgs>(pCam_ImageSavedToDisk);
ContentReadyEventArgs will be the path carrier in this case:
void pCam_ImageSavedToDisk(object sender, ContentReadyEventArgs e)
The RelativePath will be the GUID plus the extension. To show that the image is actually saved where it claims to be, use this snippet:
IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
using (IsolatedStorageFileStream stream = file.OpenFile(path, FileMode.Open))
BitmapImage image = new BitmapImage();
ImageBrush b = new ImageBrush();
b.ImageSource = image;
LayoutRoot.Background = b;
path is a field that stores the relative path. LayoutRoot is the main page grid. If everything went right, you should've noticed that the background changed to the image you just took.
Even though you successfully took the image, it is not automatically added to the media library. If you open the Pictures hub, you will notice that the Camera Roll doesn't contain your image. This is yet another task that has to be done manually.
Just like this:
pCam.AddMediaToCameraRoll(path, System.IO.Path.GetFileNameWithoutExtension(path) + "_tn.jpg");
Since I have no actual path to the thumbnail, I have to build it manually by removing the extension from the actual picture file and adding the _tn part. After this, you will see that your image is displayed in the Camera Roll. It's interesting that you can alter the thumbnail and the actual image as long as those are located in the root folder of the app isolated storage.
Same as the PhotoCamera, the VideoCamera instance saves the output to the local isolated storage in the format of a MP4 file. The naming protocol is identical, though - the same GUID application procedure is used.
Initialization is the same except for an event handler reference:
VideoCamera vCam = new VideoCamera(CameraSource.PrimaryCamera);
vCam.ThumbnailSavedToDisk += new EventHandler<ContentReadyEventArgs>(vCam_ThumbnailSavedToDisk);
Notice that instead of ImageSavedToDisk there is ThumbnailSavedToDisk, that relies on the same ContentReadyEventArgs.
The process is initiated by camera_instance.StartRecording and should be started when the camera is initialized (it is clear that the core here is the same as for PhotoCamera - after all both are using the Camera abstract class):
bool recording = false;
private void button1_Click(object sender, RoutedEventArgs e)
recording = false;
recording = true;
Here I am using the recording flag to use one Button control to switch between recording modes. Once the recording is complete, I am able get the path to the thumbnail (and therefore the video itself):
void vCam_ThumbnailSavedToDisk(object sender, ContentReadyEventArgs e)
thPath = e.RelativePath;
path = System.IO.Path.GetFileNameWithoutExtension(thPath);
path = path.Remove(path.Length - 3, 3) + ".mp4";
I am cutting the actual path to remove the thumbnail identificator (_tn) and get the actual raw GUID. Now that I have the path, I can try playing the video. For this purpose, I am going to use a MediaElement instance:
Adding the video to the Camera Roll is also done the same way as before: