Implement plugin side of sync EnumerateVideoCaptureDevices

This implements the plugin side of PPB_Flash::EnumerateVideoCaptureDevices which is a synchronous version of PPB_VideoCapture::EnumerateVideoDevices. The result is output into a PP_ArrayOutput. This also adds a unittest which does some basic testing of the messages sent, but mainly demonstrates how to write PluginResource unittests when dealing with sync messages (and adds some infrastructure to make it easy to do this).

Once VideoCapture is implemented as a new-style resource, the code for this will simplify a lot.

Review URL: https://chromiumcodereview.appspot.com/11039012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161265 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ppapi/api/private/ppb_flash.idl b/ppapi/api/private/ppb_flash.idl
index c5423d3..024796d 100644
--- a/ppapi/api/private/ppb_flash.idl
+++ b/ppapi/api/private/ppb_flash.idl
@@ -13,7 +13,8 @@
   M20_0 = 12.2,
   M20_1 = 12.3,
   M21 = 12.4,
-  M22 = 12.5
+  M22 = 12.5,
+  M24 = 12.6
 };
 
 [assert_size(4)]
@@ -22,12 +23,12 @@
    * No restrictions on Flash LSOs.
    */
   PP_FLASHLSORESTRICTIONS_NONE = 1,
-  
+
   /**
    * Don't allow access to Flash LSOs.
    */
   PP_FLASHLSORESTRICTIONS_BLOCK = 2,
-  
+
   /**
    * Store Flash LSOs in memory only.
    */
@@ -81,7 +82,7 @@
    * Specifies the number of CPU cores that are present on the system.
    */
   PP_FLASHSETTING_NUMCORES = 5,
-  
+
   /**
    * Specifies restrictions on how flash should handle LSOs. The result is an
    * int from <code>PP_FlashLSORestrictions</code>.
@@ -247,4 +248,23 @@
   PP_Bool SetCrashData([in] PP_Instance instance,
                        [in] PP_FlashCrashKey key,
                        [in] PP_Var value);
+
+  /**
+   * Enumerates video capture devices. |video_capture| is a valid
+   * PPB_VideoCapture_Dev resource. Once the operation has completed
+   * successfully, |devices| will be set up with an array of
+   * PPB_DeviceRef_Dev resources.
+   *
+   * PP_OK is returned on success and different pepper error code on failure.
+   * The ref count of the returned |devices| has already been increased by 1 for
+   * the caller.
+   *
+   * NOTE: This method is a synchronous version of |EnumerateDevices| in
+   * PPB_VideoCapture_Dev.
+   */
+  [version=12.6]
+  int32_t EnumerateVideoCaptureDevices(
+      [in] PP_Instance instance,
+      [in] PP_Resource video_capture,
+      [in] PP_ArrayOutput devices);
 };
diff --git a/ppapi/c/private/ppb_flash.h b/ppapi/c/private/ppb_flash.h
index de2ccb1..02795565 100644
--- a/ppapi/c/private/ppb_flash.h
+++ b/ppapi/c/private/ppb_flash.h
@@ -3,12 +3,13 @@
  * found in the LICENSE file.
  */
 
-/* From private/ppb_flash.idl modified Mon Jul 30 22:15:54 2012. */
+/* From private/ppb_flash.idl modified Mon Oct  8 13:03:27 2012. */
 
 #ifndef PPAPI_C_PRIVATE_PPB_FLASH_H_
 #define PPAPI_C_PRIVATE_PPB_FLASH_H_
 
 #include "ppapi/c/dev/ppb_font_dev.h"
+#include "ppapi/c/pp_array_output.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_instance.h"
 #include "ppapi/c/pp_macros.h"
@@ -27,7 +28,8 @@
 #define PPB_FLASH_INTERFACE_12_3 "PPB_Flash;12.3"
 #define PPB_FLASH_INTERFACE_12_4 "PPB_Flash;12.4"
 #define PPB_FLASH_INTERFACE_12_5 "PPB_Flash;12.5"
-#define PPB_FLASH_INTERFACE PPB_FLASH_INTERFACE_12_5
+#define PPB_FLASH_INTERFACE_12_6 "PPB_Flash;12.6"
+#define PPB_FLASH_INTERFACE PPB_FLASH_INTERFACE_12_6
 
 /**
  * @file
@@ -127,7 +129,7 @@
  * The <code>PPB_Flash</code> interface contains pointers to various functions
  * that are only needed to support Pepper Flash.
  */
-struct PPB_Flash_12_5 {
+struct PPB_Flash_12_6 {
   /**
    * Sets or clears the rendering hint that the given plugin instance is always
    * on top of page content. Somewhat more optimized painting can be used in
@@ -231,9 +233,25 @@
   PP_Bool (*SetCrashData)(PP_Instance instance,
                           PP_FlashCrashKey key,
                           struct PP_Var value);
+  /**
+   * Enumerates video capture devices. |video_capture| is a valid
+   * PPB_VideoCapture_Dev resource. Once the operation has completed
+   * successfully, |devices| will be set up with an array of
+   * PPB_DeviceRef_Dev resources.
+   *
+   * PP_OK is returned on success and different pepper error code on failure.
+   * The ref count of the returned |devices| has already been increased by 1 for
+   * the caller.
+   *
+   * NOTE: This method is a synchronous version of |EnumerateDevices| in
+   * PPB_VideoCapture_Dev.
+   */
+  int32_t (*EnumerateVideoCaptureDevices)(PP_Instance instance,
+                                          PP_Resource video_capture,
+                                          struct PP_ArrayOutput devices);
 };
 
-typedef struct PPB_Flash_12_5 PPB_Flash;
+typedef struct PPB_Flash_12_6 PPB_Flash;
 
 struct PPB_Flash_12_0 {
   void (*SetInstanceAlwaysOnTop)(PP_Instance instance, PP_Bool on_top);
@@ -372,6 +390,39 @@
   int32_t (*GetSettingInt)(PP_Instance instance, PP_FlashSetting setting);
   struct PP_Var (*GetSetting)(PP_Instance instance, PP_FlashSetting setting);
 };
+
+struct PPB_Flash_12_5 {
+  void (*SetInstanceAlwaysOnTop)(PP_Instance instance, PP_Bool on_top);
+  PP_Bool (*DrawGlyphs)(PP_Instance instance,
+                        PP_Resource pp_image_data,
+                        const struct PP_FontDescription_Dev* font_desc,
+                        uint32_t color,
+                        const struct PP_Point* position,
+                        const struct PP_Rect* clip,
+                        const float transformation[3][3],
+                        PP_Bool allow_subpixel_aa,
+                        uint32_t glyph_count,
+                        const uint16_t glyph_indices[],
+                        const struct PP_Point glyph_advances[]);
+  struct PP_Var (*GetProxyForURL)(PP_Instance instance, const char* url);
+  int32_t (*Navigate)(PP_Resource request_info,
+                      const char* target,
+                      PP_Bool from_user_action);
+  void (*RunMessageLoop)(PP_Instance instance);
+  void (*QuitMessageLoop)(PP_Instance instance);
+  double (*GetLocalTimeZoneOffset)(PP_Instance instance, PP_Time t);
+  struct PP_Var (*GetCommandLineArgs)(PP_Module module);
+  void (*PreloadFontWin)(const void* logfontw);
+  PP_Bool (*IsRectTopmost)(PP_Instance instance, const struct PP_Rect* rect);
+  int32_t (*InvokePrinting)(PP_Instance instance);
+  void (*UpdateActivity)(PP_Instance instance);
+  struct PP_Var (*GetDeviceID)(PP_Instance instance);
+  int32_t (*GetSettingInt)(PP_Instance instance, PP_FlashSetting setting);
+  struct PP_Var (*GetSetting)(PP_Instance instance, PP_FlashSetting setting);
+  PP_Bool (*SetCrashData)(PP_Instance instance,
+                          PP_FlashCrashKey key,
+                          struct PP_Var value);
+};
 /**
  * @}
  */
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
index 80480d2..f8f18bda 100644
--- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
+++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -211,6 +211,7 @@
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_12_3;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_12_4;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_12_5;
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_12_6;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_Clipboard_3_0;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_Clipboard_4_0;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_DeviceID_1_0;
@@ -2508,6 +2509,112 @@
 
 /* End wrapper methods for PPB_Flash_12_5 */
 
+/* Begin wrapper methods for PPB_Flash_12_6 */
+
+static __attribute__((pnaclcall))
+void Pnacl_M24_PPB_Flash_SetInstanceAlwaysOnTop(PP_Instance instance, PP_Bool on_top) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  iface->SetInstanceAlwaysOnTop(instance, on_top);
+}
+
+static __attribute__((pnaclcall))
+PP_Bool Pnacl_M24_PPB_Flash_DrawGlyphs(PP_Instance instance, PP_Resource pp_image_data, const struct PP_FontDescription_Dev* font_desc, uint32_t color, const struct PP_Point* position, const struct PP_Rect* clip, const float transformation[3][3], PP_Bool allow_subpixel_aa, uint32_t glyph_count, const uint16_t glyph_indices[], const struct PP_Point glyph_advances[]) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->DrawGlyphs(instance, pp_image_data, font_desc, color, position, clip, transformation, allow_subpixel_aa, glyph_count, glyph_indices, glyph_advances);
+}
+
+static __attribute__((pnaclcall))
+struct PP_Var Pnacl_M24_PPB_Flash_GetProxyForURL(PP_Instance instance, const char* url) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->GetProxyForURL(instance, url);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M24_PPB_Flash_Navigate(PP_Resource request_info, const char* target, PP_Bool from_user_action) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->Navigate(request_info, target, from_user_action);
+}
+
+static __attribute__((pnaclcall))
+void Pnacl_M24_PPB_Flash_RunMessageLoop(PP_Instance instance) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  iface->RunMessageLoop(instance);
+}
+
+static __attribute__((pnaclcall))
+void Pnacl_M24_PPB_Flash_QuitMessageLoop(PP_Instance instance) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  iface->QuitMessageLoop(instance);
+}
+
+static __attribute__((pnaclcall))
+double Pnacl_M24_PPB_Flash_GetLocalTimeZoneOffset(PP_Instance instance, PP_Time t) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->GetLocalTimeZoneOffset(instance, t);
+}
+
+static __attribute__((pnaclcall))
+struct PP_Var Pnacl_M24_PPB_Flash_GetCommandLineArgs(PP_Module module) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->GetCommandLineArgs(module);
+}
+
+static __attribute__((pnaclcall))
+void Pnacl_M24_PPB_Flash_PreloadFontWin(const void* logfontw) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  iface->PreloadFontWin(logfontw);
+}
+
+static __attribute__((pnaclcall))
+PP_Bool Pnacl_M24_PPB_Flash_IsRectTopmost(PP_Instance instance, const struct PP_Rect* rect) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->IsRectTopmost(instance, rect);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M24_PPB_Flash_InvokePrinting(PP_Instance instance) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->InvokePrinting(instance);
+}
+
+static __attribute__((pnaclcall))
+void Pnacl_M24_PPB_Flash_UpdateActivity(PP_Instance instance) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  iface->UpdateActivity(instance);
+}
+
+static __attribute__((pnaclcall))
+struct PP_Var Pnacl_M24_PPB_Flash_GetDeviceID(PP_Instance instance) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->GetDeviceID(instance);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M24_PPB_Flash_GetSettingInt(PP_Instance instance, PP_FlashSetting setting) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->GetSettingInt(instance, setting);
+}
+
+static __attribute__((pnaclcall))
+struct PP_Var Pnacl_M24_PPB_Flash_GetSetting(PP_Instance instance, PP_FlashSetting setting) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->GetSetting(instance, setting);
+}
+
+static __attribute__((pnaclcall))
+PP_Bool Pnacl_M24_PPB_Flash_SetCrashData(PP_Instance instance, PP_FlashCrashKey key, struct PP_Var value) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->SetCrashData(instance, key, value);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M24_PPB_Flash_EnumerateVideoCaptureDevices(PP_Instance instance, PP_Resource video_capture, struct PP_ArrayOutput devices) {
+  const struct PPB_Flash_12_6 *iface = Pnacl_WrapperInfo_PPB_Flash_12_6.real_iface;
+  return iface->EnumerateVideoCaptureDevices(instance, video_capture, devices);
+}
+
+/* End wrapper methods for PPB_Flash_12_6 */
+
 /* Begin wrapper methods for PPB_Flash_Clipboard_3_0 */
 
 static __attribute__((pnaclcall))
@@ -3938,6 +4045,26 @@
     .SetCrashData = (PP_Bool (*)(PP_Instance instance, PP_FlashCrashKey key, struct PP_Var value))&Pnacl_M22_PPB_Flash_SetCrashData
 };
 
+struct PPB_Flash_12_6 Pnacl_Wrappers_PPB_Flash_12_6 = {
+    .SetInstanceAlwaysOnTop = (void (*)(PP_Instance instance, PP_Bool on_top))&Pnacl_M24_PPB_Flash_SetInstanceAlwaysOnTop,
+    .DrawGlyphs = (PP_Bool (*)(PP_Instance instance, PP_Resource pp_image_data, const struct PP_FontDescription_Dev* font_desc, uint32_t color, const struct PP_Point* position, const struct PP_Rect* clip, const float transformation[3][3], PP_Bool allow_subpixel_aa, uint32_t glyph_count, const uint16_t glyph_indices[], const struct PP_Point glyph_advances[]))&Pnacl_M24_PPB_Flash_DrawGlyphs,
+    .GetProxyForURL = (struct PP_Var (*)(PP_Instance instance, const char* url))&Pnacl_M24_PPB_Flash_GetProxyForURL,
+    .Navigate = (int32_t (*)(PP_Resource request_info, const char* target, PP_Bool from_user_action))&Pnacl_M24_PPB_Flash_Navigate,
+    .RunMessageLoop = (void (*)(PP_Instance instance))&Pnacl_M24_PPB_Flash_RunMessageLoop,
+    .QuitMessageLoop = (void (*)(PP_Instance instance))&Pnacl_M24_PPB_Flash_QuitMessageLoop,
+    .GetLocalTimeZoneOffset = (double (*)(PP_Instance instance, PP_Time t))&Pnacl_M24_PPB_Flash_GetLocalTimeZoneOffset,
+    .GetCommandLineArgs = (struct PP_Var (*)(PP_Module module))&Pnacl_M24_PPB_Flash_GetCommandLineArgs,
+    .PreloadFontWin = (void (*)(const void* logfontw))&Pnacl_M24_PPB_Flash_PreloadFontWin,
+    .IsRectTopmost = (PP_Bool (*)(PP_Instance instance, const struct PP_Rect* rect))&Pnacl_M24_PPB_Flash_IsRectTopmost,
+    .InvokePrinting = (int32_t (*)(PP_Instance instance))&Pnacl_M24_PPB_Flash_InvokePrinting,
+    .UpdateActivity = (void (*)(PP_Instance instance))&Pnacl_M24_PPB_Flash_UpdateActivity,
+    .GetDeviceID = (struct PP_Var (*)(PP_Instance instance))&Pnacl_M24_PPB_Flash_GetDeviceID,
+    .GetSettingInt = (int32_t (*)(PP_Instance instance, PP_FlashSetting setting))&Pnacl_M24_PPB_Flash_GetSettingInt,
+    .GetSetting = (struct PP_Var (*)(PP_Instance instance, PP_FlashSetting setting))&Pnacl_M24_PPB_Flash_GetSetting,
+    .SetCrashData = (PP_Bool (*)(PP_Instance instance, PP_FlashCrashKey key, struct PP_Var value))&Pnacl_M24_PPB_Flash_SetCrashData,
+    .EnumerateVideoCaptureDevices = (int32_t (*)(PP_Instance instance, PP_Resource video_capture, struct PP_ArrayOutput devices))&Pnacl_M24_PPB_Flash_EnumerateVideoCaptureDevices
+};
+
 struct PPB_Flash_Clipboard_3_0 Pnacl_Wrappers_PPB_Flash_Clipboard_3_0 = {
     .IsFormatAvailable = (PP_Bool (*)(PP_Instance instance_id, PP_Flash_Clipboard_Type clipboard_type, PP_Flash_Clipboard_Format format))&Pnacl_M17_PPB_Flash_Clipboard_IsFormatAvailable,
     .ReadPlainText = (struct PP_Var (*)(PP_Instance instance_id, PP_Flash_Clipboard_Type clipboard_type))&Pnacl_M17_PPB_Flash_Clipboard_ReadPlainText,
@@ -4734,6 +4861,12 @@
   .real_iface = NULL
 };
 
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_12_6 = {
+  .iface_macro = PPB_FLASH_INTERFACE_12_6,
+  .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_Flash_12_6,
+  .real_iface = NULL
+};
+
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Flash_Clipboard_3_0 = {
   .iface_macro = PPB_FLASH_CLIPBOARD_INTERFACE_3_0,
   .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_Flash_Clipboard_3_0,
@@ -5005,6 +5138,7 @@
   &Pnacl_WrapperInfo_PPB_Flash_12_3,
   &Pnacl_WrapperInfo_PPB_Flash_12_4,
   &Pnacl_WrapperInfo_PPB_Flash_12_5,
+  &Pnacl_WrapperInfo_PPB_Flash_12_6,
   &Pnacl_WrapperInfo_PPB_Flash_Clipboard_3_0,
   &Pnacl_WrapperInfo_PPB_Flash_Clipboard_4_0,
   &Pnacl_WrapperInfo_PPB_Flash_DeviceID_1_0,
diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi
index ba6c030..ba6e8bf1 100644
--- a/ppapi/ppapi_proxy.gypi
+++ b/ppapi/ppapi_proxy.gypi
@@ -31,6 +31,8 @@
           'proxy/flash_device_id_resource.h',
           'proxy/flash_font_file_resource.cc',
           'proxy/flash_font_file_resource.h',
+          'proxy/flash_resource.cc',
+          'proxy/flash_resource.h',
           'proxy/gamepad_resource.cc',
           'proxy/gamepad_resource.h',
           'proxy/host_dispatcher.cc',
@@ -173,6 +175,7 @@
               'proxy/broker_dispatcher.cc',
               'proxy/flash_device_id_resource.cc',
               'proxy/flash_font_file_resource.cc',
+              'proxy/flash_resource.cc',
               'proxy/ppb_audio_input_proxy.cc',
               'proxy/ppb_broker_proxy.cc',
               'proxy/ppb_buffer_proxy.cc',
diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi
index 95d61dd..ef312d3d1 100644
--- a/ppapi/ppapi_shared.gypi
+++ b/ppapi/ppapi_shared.gypi
@@ -171,6 +171,7 @@
           'thunk/ppb_flash_font_file_api.h',
           'thunk/ppb_flash_font_file_thunk.cc',
           'thunk/ppb_flash_fullscreen_thunk.cc',
+          'thunk/ppb_flash_functions_api.h',
           'thunk/ppb_flash_menu_api.h',
           'thunk/ppb_flash_menu_thunk.cc',
           'thunk/ppb_flash_message_loop_api.h',
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index 9edc419..6c1d95c 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -142,6 +142,7 @@
         'proxy/run_all_unittests.cc',
 
         'proxy/file_chooser_resource_unittest.cc',
+        'proxy/flash_resource_unittest.cc',
         'proxy/mock_resource.cc',
         'proxy/mock_resource.h',
         'proxy/plugin_dispatcher_unittest.cc',
diff --git a/ppapi/proxy/flash_resource.cc b/ppapi/proxy/flash_resource.cc
new file mode 100644
index 0000000..62e97e16
--- /dev/null
+++ b/ppapi/proxy/flash_resource.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/proxy/flash_resource.h"
+
+#include "ipc/ipc_message.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/proxy/dispatch_reply_message.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/array_writer.h"
+#include "ppapi/thunk/enter.h"
+
+namespace ppapi {
+namespace proxy {
+
+FlashResource::FlashResource(Connection connection, PP_Instance instance)
+    : PluginResource(connection, instance) {
+  SendCreateToRenderer(PpapiHostMsg_Flash_Create());
+}
+
+FlashResource::~FlashResource() {
+}
+
+thunk::PPB_Flash_Functions_API* FlashResource::AsPPB_Flash_Functions_API() {
+  return this;
+}
+
+int32_t FlashResource::EnumerateVideoCaptureDevices(
+    PP_Instance instance,
+    PP_Resource video_capture,
+    const PP_ArrayOutput& devices) {
+  ArrayWriter output;
+  output.set_pp_array_output(devices);
+  if (!output.is_valid())
+    return PP_ERROR_BADARGUMENT;
+
+  thunk::EnterResource<thunk::PPB_VideoCapture_API> enter(video_capture, true);
+  if (enter.failed())
+    return PP_ERROR_NOINTERFACE;
+
+  IPC::Message reply;
+  std::vector<ppapi::DeviceRefData> device_ref_data;
+  int32_t result = CallRendererSync(
+      PpapiHostMsg_Flash_EnumerateVideoCaptureDevices(
+          enter.resource()->host_resource()), &reply);
+  if (result != PP_OK)
+    return result;
+  PpapiPluginMsg_Flash_EnumerateVideoCaptureDevicesReply::Schema::Param p;
+  if (!PpapiPluginMsg_Flash_EnumerateVideoCaptureDevicesReply::Read(&reply, &p))
+    return PP_ERROR_FAILED;
+  device_ref_data = p.a;
+
+  std::vector<scoped_refptr<Resource> > device_resources;
+  for (size_t i = 0; i < device_ref_data.size(); ++i) {
+    scoped_refptr<Resource> resource(new PPB_DeviceRef_Shared(
+        OBJECT_IS_PROXY, instance, device_ref_data[i]));
+    device_resources.push_back(resource);
+  }
+
+  if (!output.StoreResourceVector(device_resources))
+    return PP_ERROR_FAILED;
+
+  return PP_OK;
+}
+
+}  // namespace proxy
+}  // namespace ppapi
diff --git a/ppapi/proxy/flash_resource.h b/ppapi/proxy/flash_resource.h
new file mode 100644
index 0000000..b5a4428
--- /dev/null
+++ b/ppapi/proxy/flash_resource.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_PROXY_FLASH_RESOURCE_H_
+#define PPAPI_PROXY_FLASH_RESOURCE_H_
+
+#include "ppapi/proxy/connection.h"
+#include "ppapi/proxy/plugin_resource.h"
+#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/thunk/ppb_flash_functions_api.h"
+
+struct PP_ArrayOutput;
+
+namespace ppapi {
+namespace proxy {
+
+class PPAPI_PROXY_EXPORT FlashResource
+    : public PluginResource,
+      public NON_EXPORTED_BASE(thunk::PPB_Flash_Functions_API) {
+ public:
+  FlashResource(Connection connection, PP_Instance instance);
+  virtual ~FlashResource();
+
+  // Resource overrides.
+  virtual thunk::PPB_Flash_Functions_API* AsPPB_Flash_Functions_API() OVERRIDE;
+
+  // PPB_Flash_Functions_API.
+  virtual int32_t EnumerateVideoCaptureDevices(
+      PP_Instance instance,
+      PP_Resource video_capture,
+      const PP_ArrayOutput& devices) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FlashResource);
+};
+
+}  // namespace proxy
+}  // namespace ppapi
+
+#endif  // PPAPI_PROXY_FLASH_RESOURCE_H_
diff --git a/ppapi/proxy/flash_resource_unittest.cc b/ppapi/proxy/flash_resource_unittest.cc
new file mode 100644
index 0000000..901e855
--- /dev/null
+++ b/ppapi/proxy/flash_resource_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/c/dev/ppb_video_capture_dev.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/private/ppb_flash.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/ppapi_proxy_test.h"
+#include "ppapi/shared_impl/scoped_pp_resource.h"
+#include "ppapi/thunk/thunk.h"
+
+namespace ppapi {
+namespace proxy {
+
+namespace {
+
+typedef PluginProxyTest FlashResourceTest;
+
+// This simulates the creation reply message of a VideoCapture resource. This
+// won't be necessary once VideoCapture is converted to the new-style proxy.
+class VideoCaptureCreationHandler : public IPC::Listener {
+ public:
+  VideoCaptureCreationHandler(ResourceMessageTestSink* test_sink,
+                              PP_Instance instance)
+      : test_sink_(test_sink),
+        instance_(instance) {
+  }
+  virtual ~VideoCaptureCreationHandler() {}
+
+  virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
+    if (msg.type() != ::PpapiHostMsg_PPBVideoCapture_Create::ID)
+      return false;
+
+    IPC::Message* reply_msg = IPC::SyncMessage::GenerateReply(&msg);
+    HostResource resource;
+    resource.SetHostResource(instance_, 12345);
+    PpapiHostMsg_PPBVideoCapture_Create::WriteReplyParams(reply_msg, resource);
+    test_sink_->SetSyncReplyMessage(reply_msg);
+    return true;
+  }
+ private:
+  ResourceMessageTestSink* test_sink_;
+  PP_Instance instance_;
+};
+
+void* Unused(void* user_data, uint32_t element_count, uint32_t element_size) {
+  return NULL;
+}
+
+}  // namespace
+
+// Does a test of EnumerateVideoCaptureDevices() and reply functionality in
+// the plugin side using the public C interfaces.
+TEST_F(FlashResourceTest, EnumerateVideoCaptureDevices) {
+  // TODO(raymes): This doesn't actually check that the data is converted from
+  // |ppapi::DeviceRefData| to |PPB_DeviceRef| correctly, just that the right
+  // messages are sent.
+
+  // Set up a sync call handler that should return this message.
+  std::vector<ppapi::DeviceRefData> reply_device_ref_data;
+  int32_t expected_result = PP_OK;
+  PpapiPluginMsg_Flash_EnumerateVideoCaptureDevicesReply reply_msg(
+      reply_device_ref_data);
+  ResourceSyncCallHandler enumerate_video_devices_handler(
+      &sink(),
+      PpapiHostMsg_Flash_EnumerateVideoCaptureDevices::ID,
+      expected_result,
+      reply_msg);
+  sink().AddFilter(&enumerate_video_devices_handler);
+
+  // Setup the handler to simulate creation of the video resource.
+  VideoCaptureCreationHandler video_creation_handler(&sink(), pp_instance());
+  sink().AddFilter(&video_creation_handler);
+
+  // Set up the arguments to the call.
+  ScopedPPResource video_capture(ScopedPPResource::PassRef(),
+      ::ppapi::thunk::GetPPB_VideoCapture_Dev_0_2_Thunk()->Create(
+          pp_instance()));
+  std::vector<PP_Resource> unused;
+  PP_ArrayOutput output;
+  output.GetDataBuffer = &Unused;
+  output.user_data = &unused;
+
+  // Make the call.
+  const PPB_Flash_12_6* flash_iface = ::ppapi::thunk::GetPPB_Flash_12_6_Thunk();
+  int32_t actual_result = flash_iface->EnumerateVideoCaptureDevices(
+      pp_instance(), video_capture.get(), output);
+
+  // Check the result is as expected.
+  EXPECT_EQ(expected_result, actual_result);
+
+  // Should have sent an "EnumerateVideoCaptureDevices" message.
+  ASSERT_TRUE(enumerate_video_devices_handler.last_handled_msg().type() ==
+      PpapiHostMsg_Flash_EnumerateVideoCaptureDevices::ID);
+
+  // Remove the filter or it will be destroyed before the sink() is destroyed.
+  sink().RemoveFilter(&enumerate_video_devices_handler);
+  sink().RemoveFilter(&video_creation_handler);
+}
+
+}  // namespace proxy
+}  // namespace ppapi
diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc
index 51272fdd..8e05a1c 100644
--- a/ppapi/proxy/plugin_dispatcher.cc
+++ b/ppapi/proxy/plugin_dispatcher.cc
@@ -14,6 +14,7 @@
 #include "base/debug/trace_event.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/ppp_instance.h"
+#include "ppapi/proxy/flash_resource.h"
 #include "ppapi/proxy/gamepad_resource.h"
 #include "ppapi/proxy/interface_list.h"
 #include "ppapi/proxy/interface_proxy.h"
diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h
index fe2999cf..017f957 100644
--- a/ppapi/proxy/plugin_dispatcher.h
+++ b/ppapi/proxy/plugin_dispatcher.h
@@ -34,6 +34,7 @@
 
 namespace proxy {
 
+class FlashResource;
 class GamepadResource;
 class ResourceMessageReplyParams;
 
@@ -49,8 +50,10 @@
   // When non-NULL, indicates the callback to execute when mouse lock is lost.
   scoped_refptr<TrackedCallback> mouse_lock_callback;
 
-  // Lazily created the first time the plugin requests gamepad data.
+  // The following are lazily created the first time the plugin requests them.
+  // (These are singleton-style resources).
   scoped_refptr<GamepadResource> gamepad_resource;
+  scoped_refptr<FlashResource> flash_resource;
 
   // Calls to |RequestSurroundingText()| are done by posted tasks. Track whether
   // a) a task is pending, to avoid redundant calls, and b) whether we should
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 863cc4c6..238564c 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -1675,4 +1675,11 @@
                      uint32_t /* table */)
 IPC_MESSAGE_CONTROL1(PpapiPluginMsg_FlashFontFile_GetFontTableReply,
                      std::string /* output */)
+
+// Flash functions.
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_Flash_Create)
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_Flash_EnumerateVideoCaptureDevices,
+                     ppapi::HostResource /* video_capture */)
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Flash_EnumerateVideoCaptureDevicesReply,
+                     std::vector<ppapi::DeviceRefData> /* devices */)
 #endif  // !defined(OS_NACL) && !defined(NACL_WIN64)
diff --git a/ppapi/proxy/ppb_flash_proxy.h b/ppapi/proxy/ppb_flash_proxy.h
index 03ecf89..477b1ae 100644
--- a/ppapi/proxy/ppb_flash_proxy.h
+++ b/ppapi/proxy/ppb_flash_proxy.h
@@ -32,6 +32,11 @@
 struct SerializedDirEntry;
 class SerializedVarReturnValue;
 
+/////////////////////////// WARNING:DEPRECTATED ////////////////////////////////
+// Please do not add any new functions to this proxy. They should be
+// implemented in the new-style resource proxy (see flash_resource.h).
+// TODO(raymes): All of these functions should be moved to the new-style proxy.
+////////////////////////////////////////////////////////////////////////////////
 class PPB_Flash_Proxy : public InterfaceProxy, public PPB_Flash_Shared {
  public:
   explicit PPB_Flash_Proxy(Dispatcher* dispatcher);
diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc
index 5f0c1633..3734512 100644
--- a/ppapi/proxy/ppb_instance_proxy.cc
+++ b/ppapi/proxy/ppb_instance_proxy.cc
@@ -4,6 +4,7 @@
 
 #include "ppapi/proxy/ppb_instance_proxy.h"
 
+#include "build/build_config.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/pp_time.h"
 #include "ppapi/c/pp_var.h"
@@ -14,6 +15,7 @@
 #include "ppapi/c/private/pp_content_decryptor.h"
 #include "ppapi/proxy/content_decryptor_private_serializer.h"
 #include "ppapi/proxy/enter_proxy.h"
+#include "ppapi/proxy/flash_resource.h"
 #include "ppapi/proxy/gamepad_resource.h"
 #include "ppapi/proxy/host_dispatcher.h"
 #include "ppapi/proxy/plugin_dispatcher.h"
@@ -313,6 +315,28 @@
   return static_cast<PPB_Flash_Proxy*>(ip);
 }
 
+thunk::PPB_Flash_Functions_API* PPB_Instance_Proxy::GetFlashFunctionsAPI(
+    PP_Instance instance) {
+#if !defined(OS_NACL) && !defined(NACL_WIN64)
+  InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())->
+      GetInstanceData(instance);
+  if (!data)
+    return NULL;
+
+  if (!data->flash_resource.get()) {
+    Connection connection(
+        PluginGlobals::Get()->plugin_proxy_delegate()->GetBrowserSender(),
+        dispatcher());
+    data->flash_resource = new FlashResource(connection, instance);
+  }
+  return data->flash_resource.get();
+#else
+  // Flash functions aren't implemented for nacl.
+  NOTIMPLEMENTED();
+  return NULL;
+#endif  // !defined(OS_NACL) && !defined(NACL_WIN64)
+}
+
 thunk::PPB_Gamepad_API* PPB_Instance_Proxy::GetGamepadAPI(
     PP_Instance instance) {
   InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())->
diff --git a/ppapi/proxy/ppb_instance_proxy.h b/ppapi/proxy/ppb_instance_proxy.h
index 61155b6d..274d1e30 100644
--- a/ppapi/proxy/ppb_instance_proxy.h
+++ b/ppapi/proxy/ppb_instance_proxy.h
@@ -70,6 +70,8 @@
   virtual PP_Bool GetScreenSize(PP_Instance instance,
                                 PP_Size* size) OVERRIDE;
   virtual thunk::PPB_Flash_API* GetFlashAPI() OVERRIDE;
+  virtual thunk::PPB_Flash_Functions_API* GetFlashFunctionsAPI(
+      PP_Instance instance) OVERRIDE;
   virtual thunk::PPB_Gamepad_API* GetGamepadAPI(PP_Instance instance) OVERRIDE;
   virtual int32_t RequestInputEvents(PP_Instance instance,
                                      uint32_t event_classes) OVERRIDE;
diff --git a/ppapi/proxy/resource_message_test_sink.cc b/ppapi/proxy/resource_message_test_sink.cc
index 7daf435..a2920e3f 100644
--- a/ppapi/proxy/resource_message_test_sink.cc
+++ b/ppapi/proxy/resource_message_test_sink.cc
@@ -42,6 +42,30 @@
 ResourceMessageTestSink::~ResourceMessageTestSink() {
 }
 
+bool ResourceMessageTestSink::Send(IPC::Message* msg) {
+  int message_id = 0;
+  scoped_ptr<IPC::MessageReplyDeserializer> reply_deserializer;
+  if (msg->is_sync()) {
+    reply_deserializer.reset(
+        static_cast<IPC::SyncMessage*>(msg)->GetReplyDeserializer());
+    message_id = IPC::SyncMessage::GetMessageId(*msg);
+  }
+  bool result = IPC::TestSink::Send(msg);  // Deletes |msg|.
+  if (sync_reply_msg_.get()) {
+    // |sync_reply_msg_| should always be a reply to the pending sync message.
+    DCHECK(IPC::SyncMessage::IsMessageReplyTo(*sync_reply_msg_.get(),
+                                              message_id));
+    reply_deserializer->SerializeOutputParameters(*sync_reply_msg_.get());
+    sync_reply_msg_.reset(NULL);
+  }
+  return result;
+}
+
+void ResourceMessageTestSink::SetSyncReplyMessage(IPC::Message* reply_msg) {
+  DCHECK(!sync_reply_msg_.get());
+  sync_reply_msg_.reset(reply_msg);
+}
+
 bool ResourceMessageTestSink::GetFirstResourceCallMatching(
     uint32 id,
     ResourceMessageCallParams* params,
@@ -60,5 +84,43 @@
       *this, id, params, nested_msg);
 }
 
+ResourceSyncCallHandler::ResourceSyncCallHandler(
+    ResourceMessageTestSink* test_sink,
+    uint32 incoming_type,
+    int32_t result,
+    const IPC::Message& reply_msg)
+    : test_sink_(test_sink),
+      incoming_type_(incoming_type),
+      result_(result),
+      reply_msg_(reply_msg) {
+}
+
+ResourceSyncCallHandler::~ResourceSyncCallHandler() {
+}
+
+bool ResourceSyncCallHandler::OnMessageReceived(const IPC::Message& msg) {
+  if (msg.type() != PpapiHostMsg_ResourceSyncCall::ID)
+    return false;
+  PpapiHostMsg_ResourceSyncCall::Schema::SendParam send_params;
+  bool success = PpapiHostMsg_ResourceSyncCall::ReadSendParam(
+      &msg, &send_params);
+  DCHECK(success);
+  ResourceMessageCallParams call_params = send_params.a;
+  IPC::Message call_msg = send_params.b;
+  if (call_msg.type() != incoming_type_)
+    return false;
+  IPC::Message* wrapper_reply_msg = IPC::SyncMessage::GenerateReply(&msg);
+  ResourceMessageReplyParams reply_params(call_params.pp_resource(),
+                                          call_params.sequence());
+  reply_params.set_result(result_);
+  PpapiHostMsg_ResourceSyncCall::WriteReplyParams(
+      wrapper_reply_msg, reply_params, reply_msg_);
+  test_sink_->SetSyncReplyMessage(wrapper_reply_msg);
+
+  // Stash a copy of the message for inspection later.
+  last_handled_msg_ = call_msg;
+  return true;
+}
+
 }  // namespace proxy
 }  // namespace ppapi
diff --git a/ppapi/proxy/resource_message_test_sink.h b/ppapi/proxy/resource_message_test_sink.h
index bf74bec..7694fb0 100644
--- a/ppapi/proxy/resource_message_test_sink.h
+++ b/ppapi/proxy/resource_message_test_sink.h
@@ -6,6 +6,7 @@
 #define PPAPI_PROXY_RESOURCE_MESSAGE_TEST_SINK_H_
 
 #include "ipc/ipc_test_sink.h"
+#include "ppapi/c/pp_stdint.h"
 
 namespace ppapi {
 namespace proxy {
@@ -20,6 +21,14 @@
   ResourceMessageTestSink();
   virtual ~ResourceMessageTestSink();
 
+  // IPC::TestSink.
+  // Overridden to handle sync messages.
+  virtual bool Send(IPC::Message* msg) OVERRIDE;
+
+  // Sets the reply message that will be returned to the next sync message sent.
+  // This test sink owns any reply messages passed into this method.
+  void SetSyncReplyMessage(IPC::Message* reply_msg);
+
   // Searches the queue for the first resource call message with a nested
   // message matching the given ID. On success, returns true and populates the
   // givem params and nested message.
@@ -33,6 +42,46 @@
       uint32 id,
       ResourceMessageReplyParams* params,
       IPC::Message* nested_msg);
+
+ private:
+  scoped_ptr<IPC::Message> sync_reply_msg_;
+};
+
+// This is a message handler which generates reply messages for synchronous
+// resource calls. This allows unit testing of the plugin side of resources
+// which send sync messages. If you want to reply to a sync message type named
+// |PpapiHostMsg_X_Y| with |PpapiPluginMsg_X_YReply| then usage would be as
+// follows (from within |PluginProxyTest|s):
+//
+// PpapiHostMsg_X_YReply my_reply;
+// ResourceSyncCallHandler handler(&sink(),
+//                                 PpapiHostMsg_X_Y::ID,
+//                                 PP_OK,
+//                                 my_reply);
+// sink().AddFilter(&handler);
+// // Do stuff to send a sync message ...
+// // You can check handler.last_handled_msg() to ensure the correct message was
+// // handled.
+// sink().RemoveFilter(&handler);
+class ResourceSyncCallHandler : public IPC::Listener {
+ public:
+  ResourceSyncCallHandler(ResourceMessageTestSink* test_sink,
+                          uint32 incoming_type,
+                          int32_t result,
+                          const IPC::Message& reply_msg);
+  virtual ~ResourceSyncCallHandler();
+
+  // IPC::Listener.
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+  IPC::Message last_handled_msg() { return last_handled_msg_; }
+
+ private:
+  ResourceMessageTestSink* test_sink_;
+  uint32 incoming_type_;
+  int32_t result_;
+  IPC::Message reply_msg_;
+  IPC::Message last_handled_msg_;
 };
 
 }  // namespace proxy
diff --git a/ppapi/shared_impl/resource.h b/ppapi/shared_impl/resource.h
index f14d988..442f1ce 100644
--- a/ppapi/shared_impl/resource.h
+++ b/ppapi/shared_impl/resource.h
@@ -37,6 +37,7 @@
   F(PPB_Find_API) \
   F(PPB_Flash_DeviceID_API) \
   F(PPB_Flash_FontFile_API) \
+  F(PPB_Flash_Functions_API) \
   F(PPB_Flash_Menu_API) \
   F(PPB_Flash_MessageLoop_API) \
   F(PPB_Graphics2D_API) \
diff --git a/ppapi/thunk/interfaces_ppb_private_flash.h b/ppapi/thunk/interfaces_ppb_private_flash.h
index 91e50cd..7a3b423 100644
--- a/ppapi/thunk/interfaces_ppb_private_flash.h
+++ b/ppapi/thunk/interfaces_ppb_private_flash.h
@@ -26,6 +26,9 @@
 PROXIED_IFACE(PPB_Flash,
               PPB_FLASH_INTERFACE_12_5,
               PPB_Flash_12_5)
+PROXIED_IFACE(PPB_Flash,
+              PPB_FLASH_INTERFACE_12_6,
+              PPB_Flash_12_6)
 
 PROXIED_IFACE(PPB_Flash,
               PPB_FLASH_CLIPBOARD_INTERFACE_3_LEGACY,
diff --git a/ppapi/thunk/ppb_flash_api.h b/ppapi/thunk/ppb_flash_api.h
index d39393e86..7a1a641 100644
--- a/ppapi/thunk/ppb_flash_api.h
+++ b/ppapi/thunk/ppb_flash_api.h
@@ -16,6 +16,13 @@
 
 namespace thunk {
 
+/////////////////////////// WARNING:DEPRECTATED ////////////////////////////////
+// Please do not add any new functions to this API. They should be implemented
+// in the new-style resource proxy (see flash_functions_api.h and
+// flash_resource.h).
+// TODO(raymes): All of these functions should be moved to
+// flash_functions_api.h.
+////////////////////////////////////////////////////////////////////////////////
 // This class collects all of the Flash interface-related APIs into one place.
 class PPAPI_THUNK_EXPORT PPB_Flash_API {
  public:
diff --git a/ppapi/thunk/ppb_flash_functions_api.h b/ppapi/thunk/ppb_flash_functions_api.h
new file mode 100644
index 0000000..2a4a24e
--- /dev/null
+++ b/ppapi/thunk/ppb_flash_functions_api.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_THUNK_PPB_FLASH_FUNCTIONS_API_H_
+#define PPAPI_THUNK_PPB_FLASH_FUNCTIONS_API_H_
+
+#include "ppapi/thunk/ppapi_thunk_export.h"
+
+struct PP_ArrayOutput;
+
+namespace ppapi {
+namespace thunk {
+
+// This class collects all of the Flash interface-related APIs into one place.
+// PPB_Flash_API is deprecated in favor of this (the new resource model uses
+// this API).
+class PPAPI_THUNK_EXPORT PPB_Flash_Functions_API {
+ public:
+  virtual ~PPB_Flash_Functions_API() {}
+
+ // PPB_Flash.
+ virtual int32_t EnumerateVideoCaptureDevices(
+     PP_Instance instance,
+     PP_Resource video_capture,
+     const PP_ArrayOutput& devices) = 0;
+};
+
+}  // namespace thunk
+}  // namespace ppapi
+
+#endif // PPAPI_THUNK_PPB_FLASH_FUNCTIONS_API_H_
diff --git a/ppapi/thunk/ppb_flash_thunk.cc b/ppapi/thunk/ppb_flash_thunk.cc
index 85ca393..b95a724 100644
--- a/ppapi/thunk/ppb_flash_thunk.cc
+++ b/ppapi/thunk/ppb_flash_thunk.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ppapi/c/pp_array_output.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/private/ppb_flash.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
@@ -9,6 +10,7 @@
 #include "ppapi/shared_impl/var.h"
 #include "ppapi/thunk/enter.h"
 #include "ppapi/thunk/ppb_flash_api.h"
+#include "ppapi/thunk/ppb_flash_functions_api.h"
 #include "ppapi/thunk/ppb_instance_api.h"
 #include "ppapi/thunk/thunk.h"
 
@@ -153,6 +155,23 @@
   return enter.functions()->GetFlashAPI()->SetCrashData(instance, key, value);
 }
 
+int32_t EnumerateVideoCaptureDevices(PP_Instance instance,
+                                     PP_Resource video_capture,
+                                     PP_ArrayOutput devices) {
+  EnterInstance enter(instance);
+  if (enter.succeeded()) {
+    PPB_Flash_Functions_API* api =
+        enter.functions()->GetFlashFunctionsAPI(instance);
+    if (api) {
+      return api->EnumerateVideoCaptureDevices(instance, video_capture,
+                                               devices);
+    } else {
+      return PP_ERROR_NOINTERFACE;
+    }
+  }
+  return PP_ERROR_BADRESOURCE;
+}
+
 const PPB_Flash_12_0 g_ppb_flash_12_0_thunk = {
   &SetInstanceAlwaysOnTop,
   &DrawGlyphs,
@@ -250,6 +269,26 @@
   &SetCrashData
 };
 
+const PPB_Flash_12_6 g_ppb_flash_12_6_thunk = {
+  &SetInstanceAlwaysOnTop,
+  &DrawGlyphs,
+  &GetProxyForURL,
+  &Navigate,
+  &RunMessageLoop,
+  &QuitMessageLoop,
+  &GetLocalTimeZoneOffset,
+  &GetCommandLineArgs,
+  &PreLoadFontWin,
+  &IsRectTopmost,
+  &InvokePrinting,
+  &UpdateActivity,
+  &GetDeviceID,
+  &GetSettingInt,
+  &GetSetting,
+  &SetCrashData,
+  &EnumerateVideoCaptureDevices
+};
+
 }  // namespace
 
 const PPB_Flash_12_0* GetPPB_Flash_12_0_Thunk() {
@@ -276,5 +315,9 @@
   return &g_ppb_flash_12_5_thunk;
 }
 
+const PPB_Flash_12_6* GetPPB_Flash_12_6_Thunk() {
+  return &g_ppb_flash_12_6_thunk;
+}
+
 }  // namespace thunk
 }  // namespace ppapi
diff --git a/ppapi/thunk/ppb_instance_api.h b/ppapi/thunk/ppb_instance_api.h
index b919e31..3038c68 100644
--- a/ppapi/thunk/ppb_instance_api.h
+++ b/ppapi/thunk/ppb_instance_api.h
@@ -37,6 +37,7 @@
 namespace thunk {
 
 class PPB_Flash_API;
+class PPB_Flash_Functions_API;
 class PPB_Gamepad_API;
 
 class PPB_Instance_API {
@@ -87,8 +88,11 @@
                                 PP_Bool fullscreen) = 0;
   virtual PP_Bool GetScreenSize(PP_Instance instance, PP_Size* size) = 0;
 
-  // Flash.
+  // Flash (Deprecated for Flash_Functions).
   virtual PPB_Flash_API* GetFlashAPI() = 0;
+  // Flash_Functions
+  virtual PPB_Flash_Functions_API* GetFlashFunctionsAPI(
+      PP_Instance instance) = 0;
 
   // Gamepad.
   virtual PPB_Gamepad_API* GetGamepadAPI(PP_Instance instance) = 0;