What hook can I use to modify Views Datasource JSON output?
I find my 1st answer informative regarding auxillery information regarding views and views_datasource. So here's 1 way I think you get the url you want.

You said:


  My guess is that Views Datasource is processing the data after I've
  seen it in my hook implementations.


It is, look at what views_json_view_pre_render() is doing:

function views_json_views_pre_render(&amp;$view) {
  if(isset($view-&gt;plugin_name) &amp;&amp; $view-&gt;plugin_name == 'views_json') {
    // Support for Video field.
    if(!empty($view-&gt;result)) {
      // Process each View result.
      foreach($view-&gt;result as $row =&gt; $result) {
        // Only process the entity fields defined by the View.
        foreach($view-&gt;field as $field_name =&gt; $field) {
          if($field instanceof views_handler_field_field) {
            if($field-&gt;field_info['type'] == 'video') {

              // Get the Video URL.
              $video = $field-&gt;get_value($view-&gt;result[$row]);
              // -- See this line !!
              $url = file_create_url($video[0]['uri']);
              $render_array = array(
                '#type' =&gt; 'markup',
                '#markup' =&gt; filter_xss($url),
              );
              // Substitute embed code with URL. @todo Add support for escaped embed codes.
              // See this line !!
              $view-&gt;result[$row]-&gt;{'field_'. $field_name}[0]['rendered'] = $render_array;
            }


If its a video field views_json is taking each of the results and replacing the embed code with the URL of the video. This is what  you're seeing.

So how do you fix this. You write your own hook_views_pre_render() that runs before views_json's pre render. In your pre render function you change $video[0]['uri'] to whatever url you want -- ultimately thats the value views_json will use. If you can get the FID or the full url to the image here you should be able to easily set that value.

So in your own module you'd write 2 functions:

// File: mymodule.install
function MYMODULE_install() {
// Set the weight of the mymodule.module to a value lower than views_datasource's views_json module.
  db_update('system')
   -&gt;fields(array('weight' =&gt; -1))
   -&gt;condition('name', 'mymodule')
   -&gt;execute();
}


// File: mymodule.module
/**
 * Implements hook_views_pre_render().
 */
function mymodule_views_pre_render(&amp;$view) {
  if(isset($view-&gt;plugin_name) &amp;&amp; $view-&gt;plugin_name == 'views_json' &amp;&amp; $view-&gt;name == 'YOUR_SPECIFIC_VIEW') {
    // Support for Video field.
    if(!empty($view-&gt;result)) {
      // Process each View result.
      foreach($view-&gt;result as $row =&gt; $result) {
        // Only process the entity fields defined by the View.
        foreach($view-&gt;field as $field_name =&gt; $field) {
          if($field instanceof views_handler_field_field) {
            if($field-&gt;field_info['type'] == 'video') {
              // Change the video uri to the image you want ...
              $view-&gt;result[$row][0]['uri'] = /* some logic here */;
            }
          }
        }
      }
    }
  }
}


Your pre render hook will run before views_datasource's. It simply alters the url to whatever you want. Then views_datasource's views_json hook runs and just uses it as its supposed to -- you just slipped in the correct value. This should work. Code is untested.