diff --git a/includes/media.filter.inc b/includes/media.filter.inc
index 6b7f51a..38c78c7 100644
--- a/includes/media.filter.inc
+++ b/includes/media.filter.inc
@@ -7,6 +7,9 @@
  * @TODO: Rename this file?
  */
 
+define('MEDIA_TOKEN_REGEX', '/\[\[.*?\]\]/s');
+define('MEDIA_TOKEN_REGEX_ALT', '/%7B.*?%7D/s');
+
 /**
  * Implements hook_wysiwyg_include_directory().
  */
@@ -19,6 +22,182 @@ function media_wysiwyg_include_directory($type) {
 }
 
 /**
+ * Implements hook_field_attach_insert().
+ *
+ * Track file usage for media files included in formatted text. Note that this
+ * is heavy-handed, and should be replaced when Drupal's filter system is
+ * context-aware.
+ */
+function media_field_attach_insert($entity_type, $entity) {
+  _media_filter_add_file_usage_from_fields($entity_type, $entity);
+}
+
+/**
+ * Implements hook_field_attach_update().
+ *
+ * @see media_field_attach_insert().
+ */
+function media_field_attach_update($entity_type, $entity) {
+  _media_filter_add_file_usage_from_fields($entity_type, $entity);
+}
+
+/**
+ * Add file usage from file references in an entity's text fields.
+ */
+function _media_filter_add_file_usage_from_fields($entity_type, $entity) {
+  // Track the total usage for files from all fields combined.
+  $entity_files = media_entity_field_count_files($entity_type, $entity);
+
+  list($entity_id, $entity_vid, $entity_bundle) = entity_extract_ids($entity_type, $entity);
+
+  // When an entity has revisions and then is saved again NOT as new version the
+  // previous revision of the entity has be loaded to get the last known good
+  // count of files. The saved data is compared against the last version
+  // so that a correct file count can be created for that (the current) version
+  // id. This code may assume some things about entities that are only true for
+  // node objects. This should be reviewed.
+  // @TODO this conditional can probably be condensed
+  if (empty($entity->revision) && empty($entity->old_vid) && empty($entity->is_new) && ! empty($entity->original)) {
+    $old_files = media_entity_field_count_files($entity_type, $entity->original);
+    foreach ($old_files as $fid => $old_file_count) {
+      // Were there more files on the node just prior to saving?
+      if (empty($entity_files[$fid])) {
+        $entity_files[$fid] = 0;
+      }
+      if ($old_file_count > $entity_files[$fid]) {
+        $deprecate = $old_file_count - $entity_files[$fid];
+        // Now deprecate this usage
+        $file = file_load($fid);
+        file_usage_delete($file, 'media', $entity_type, $entity_id, $deprecate);
+        // Usage is deleted, nothing more to do with this file
+        unset($entity_files[$fid]);
+      }
+      // There are the same number of files, nothing to do
+      elseif ($entity_files[$fid] ==  $old_file_count) {
+        unset($entity_files[$fid]);
+      }
+      // There are more files now, adjust the difference for the greater number.
+      // file_usage incrementing will happen below.
+      else {
+        // We just need to adjust what the file count will account for the new
+        // images that have been added since the increment process below will
+        // just add these additional ones in
+        $entity_files[$fid] = $entity_files[$fid] - $old_file_count;
+      }
+    }
+  }
+
+  // Each entity revision counts for file usage. If versions are not enabled
+  // the file_usage table will have no entries for this because of the delete
+  // query above.
+  foreach ($entity_files as $fid => $entity_count) {
+    $file = file_load($fid);
+    file_usage_add($file, 'media', $entity_type, $entity_id, $entity_count);
+  }
+
+}
+
+/**
+ * Parse file references from an entity's text fields and return them as an array.
+ */
+function media_filter_parse_from_fields($entity_type, $entity) {
+  $file_references = array();
+
+  foreach (_media_filter_fields_with_text_filtering($entity_type, $entity) as $field_name) {
+    if ($field_items = field_get_items($entity_type, $entity, $field_name)) {
+      foreach ($field_items as $field_item) {
+        preg_match_all(MEDIA_TOKEN_REGEX, $field_item['value'], $matches);
+        foreach ($matches[0] as $tag) {
+          $tag = str_replace(array('[[', ']]'), '', $tag);
+          $tag_info = drupal_json_decode($tag);
+          if (isset($tag_info['fid']) && $tag_info['type'] == 'media') {
+            $file_references[] = $tag_info;
+          }
+        }
+
+        preg_match_all(MEDIA_TOKEN_REGEX_ALT, $field_item['value'], $matches_alt);
+        foreach ($matches_alt[0] as $tag) {
+          $tag = urldecode($tag);
+          $tag_info = drupal_json_decode($tag);
+          if (isset($tag_info['fid']) && $tag_info['type'] == 'media') {
+            $file_references[] = $tag_info;
+          }
+        }
+      }
+    }
+  }
+
+  return $file_references;
+}
+
+/**
+ * Returns an array containing the names of all fields that perform text filtering.
+ */
+function _media_filter_fields_with_text_filtering($entity_type, $entity) {
+  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
+  $fields = field_info_instances($entity_type, $bundle);
+
+  // Get all of the fields on this entity that allow text filtering.
+  $fields_with_text_filtering = array();
+  foreach ($fields as $field_name => $field) {
+    if (!empty($field['settings']['text_processing'])) {
+      $fields_with_text_filtering[] = $field_name;
+    }
+  }
+
+  return $fields_with_text_filtering;
+}
+
+/**
+ * Utility function to get the file count in this entity
+ *
+ * @param type $entity
+ * @param type $entity_type
+ * @return int
+ */
+function media_entity_field_count_files($entity_type, $entity) {
+  $entity_files = array();
+  foreach (media_filter_parse_from_fields($entity_type, $entity) as $file_reference) {
+    if (empty($entity_files[$file_reference['fid']])) {
+      $entity_files[$file_reference['fid']] = 1;
+    }
+    else {
+      $entity_files[$file_reference['fid']]++;
+    }
+  }
+  return $entity_files;
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function media_entity_delete($entity, $type) {
+  list($entity_id) = entity_extract_ids($type, $entity);
+
+  db_delete('file_usage')
+    ->condition('module', 'media')
+    ->condition('type', $type)
+    ->condition('id', $entity_id)
+    ->execute();
+}
+
+/**
+ * Implements hook_field_attach_delete_revision().
+ *
+ * @param type $entity_type
+ * @param type $entity
+ */
+function media_field_attach_delete_revision($entity_type, $entity) {
+  list($entity_id) = entity_extract_ids($entity_type, $entity);
+  $files = media_entity_field_count_files($entity_type, $entity);
+  foreach ($files as $fid => $count) {
+    if ($file = file_load($fid)) {
+      file_usage_delete($file, 'media', $entity_type , $entity_id, $count);
+    }
+  }
+}
+
+/**
  * Filter callback for media markup filter.
  *
  * @TODO check for security probably pass text through filter_xss
@@ -26,8 +205,7 @@ function media_wysiwyg_include_directory($type) {
  */
 function media_filter($text) {
   $text = ' ' . $text . ' ';
-  $text = preg_replace_callback("/\[\[.*?\]\]/s", 'media_token_to_markup', $text);
-
+  $text = preg_replace_callback(MEDIA_TOKEN_REGEX, 'media_token_to_markup', $text);
   return $text;
 }
 
diff --git a/media.info b/media.info
index 6b37c4f..7a159cd 100644
--- a/media.info
+++ b/media.info
@@ -7,4 +7,5 @@ dependencies[] = image
 files[] = includes/MediaReadOnlyStreamWrapper.inc
 files[] = test/media.types.test
 files[] = test/media.entity.test
+files[] = test/media.file.usage.test
 configure = admin/config/media/browser
diff --git a/test/media.file.usage.test b/test/media.file.usage.test
new file mode 100644
index 0000000..6dc81d0
--- /dev/null
+++ b/test/media.file.usage.test
@@ -0,0 +1,268 @@
+<?php
+
+/**
+ * @file
+ * Tests for the file usage in entity fields with the Media filter markup.
+ */
+
+class MediaFileUsageTest extends MediaTestHelper {
+
+  /**
+   * Provide test information.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => t('File usage tracking'),
+      'description' => t('Tests tracking of usage for files in text fields.'),
+      'group' => t('Media'),
+    );
+  }
+
+  /**
+   * Enable media and file entity modules for testing.
+   */
+  public function setUp() {
+    parent::setUp(array('media', 'file_entity'));
+
+    // Create and log in a user.
+    $account = $this->drupalCreateUser(array('administer nodes', 'create article content'));
+    $this->drupalLogin($account);
+  }
+
+  /**
+    * Generates markup to be inserted for a file.
+    *
+    * This is a PHP version of InsertMedia.insert() from js/wysiwyg-media.js.
+    *
+    * @param int $fid
+    *   Drupal file id
+    * @param int $count
+    *   Quantity of markup to insert
+    *
+    * @return string
+    *   Filter markup.
+    */
+  private function generateFileMarkup($fid, $count = 1) {
+    $file_usage_markup = '';
+
+    // Build the data that is used in a media tag.
+    $data = array(
+      'fid' => $fid,
+      'type' => 'media',
+      'view_mode' => 'preview',
+      'attributes' => array(
+        'height' => 100,
+        'width' => 100,
+        'classes' => 'media-element file_preview',
+      )
+    );
+
+    // Create the file usage markup.
+    for ($i = 1; $i <= $count; $i++) {
+      $file_usage_markup .= '<p>[[' . drupal_json_encode($data) . ']]</p>';
+    }
+
+    return $file_usage_markup;
+  }
+
+
+  /**
+   * Utility function to create a test node.
+   *
+   * @param int $fid
+   *   Create the node with media markup in the body field
+   *
+   * @return int
+   *   Returns the node id
+   */
+  private function createNode($fid = FALSE) {
+    $markup = '';
+    if (! empty($fid)) {
+      $markup = $this->generateFileMarkup($fid);
+    }
+
+    // Create an article node with file markup in the body field.
+    $edit = array(
+      'title' => $this->randomName(8),
+      'body[und][0][value]' => $markup,
+    );
+    // Save the article node. First argument is the URL, then the value array
+    // and the third is the label the button that should be "clicked".
+    $this->drupalPost('node/add/article', $edit, t('Save'));
+
+    // Get the article node that was saved by the unique title.
+    $node = $this->drupalGetNodeByTitle($edit['title']);
+    return $node->nid;
+  }
+
+  /**
+   * Tests the tracking of file usages for files submitted via the WYSIWYG editor.
+   */
+  public function testFileUsageIncrementing() {
+    // Create a file.
+    $files = $this->drupalGetTestFiles('image');
+    $file = file_save($files[0]);
+    $fid = $file->fid;
+
+    // There should be zero usages of this file prior to node creation,
+    $file_uses = file_usage_list($file);
+    $this->assertEqual(empty($file_uses), TRUE, t('Created a new file with zero uses.'));
+
+    // Create a node to test with.
+    $nid = $this->createNode($fid);
+
+    // Get the new file usage count.
+    $file_uses = file_usage_list($file);
+
+    $this->assertEqual($file_uses['media']['node'][$nid], 1, t('File usage increases when added to a new node.'));
+
+    // Create a new revision that has the file on it. File usage will be 2.
+    $node = node_load($nid);
+    $node->revision = TRUE;
+    node_save($node);
+
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+    $revisions = count(node_revision_list($node));
+    // Keep track of this VID to test deletion later on.
+    $delete_one = $node->vid;
+
+    $this->assertEqual($revisions, 2, t('Node save created a second revision'));
+    $this->assertEqual($file_uses['media']['node'][$nid], 2, t('File usage incremented with a new node revision.'));
+
+    // Create a new revision that has two instances of the file. File usage will
+    // be 4.
+    $node = node_load($nid);
+    $node->body[LANGUAGE_NONE][0]['value'] = $this->generateFileMarkup($fid, 2);
+    $node->revision = TRUE;
+    node_save($node);
+
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+    $revisions = count(node_revision_list($node));
+    // Keep track of this VID to test deletion later on.
+    $delete_two = $node->vid;
+
+    $this->assertEqual($revisions, 3, t('Node save created a third revision.'));
+    $this->assertEqual($file_uses['media']['node'][$nid], 4, t('File usage incremented with multiple files and a new node revision.'));
+
+    // Create a new revision that has no file on it. File usage will be 4.
+    $node = node_load($nid);
+    $node->body[LANGUAGE_NONE][0]['value'] = '';
+    $node->revision = TRUE;
+    node_save($node);
+
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+    $revisions = count(node_revision_list($node));
+    // Keep track of this VID to test deletion later on.
+    $delete_zero = $node->vid;
+
+    $this->assertEqual($revisions, 4, t('Node save created a fourth revision.'));
+    $this->assertEqual($file_uses['media']['node'][$nid], 4, t('File usage does not change with a new revision of the node without the file'));
+
+    // Create a new revision that has the file on it. File usage will be 5.
+    $node = node_load($nid);
+    $node->body[LANGUAGE_NONE][0]['value'] = $this->generateFileMarkup($fid, 1);
+    $node->revision = TRUE;
+    node_save($node);
+
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+    $revisions = count(node_revision_list($node));
+
+    $this->assertEqual($revisions, 5, t('Node save created a new revision.'));
+    $this->assertEqual($file_uses['media']['node'][$nid], 5, t('File usage incremented with a single file on a new node revision.'));
+
+    // Delete a revision that has the file on it once. File usage will be 4.
+    node_revision_delete($delete_one);
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+    $this->assertEqual($file_uses['media']['node'][$nid], 4, t('Deleting revision with file decreases file usage'));
+
+    // Delete a revision that has no file on it. File usage will be 4.
+    node_revision_delete($delete_zero);
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+    $this->assertEqual($file_uses['media']['node'][$nid], 4, t('Deleting revision without a file does not change file usage.'));
+
+    // Delete a revision that has the file on it twice. File usage will be 2.
+    node_revision_delete($delete_two);
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+    $this->assertEqual($file_uses['media']['node'][$nid], 2, t('Deleting revision with file decreases file usage'));
+
+    // Create a new revision with the file on it twice. File usage will be 4.
+    $node = node_load($nid);
+    $node->body[LANGUAGE_NONE][0]['value'] = $this->generateFileMarkup($fid, 2);
+    $node->revision = TRUE;
+    node_save($node);
+
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+
+    $this->assertEqual($file_uses['media']['node'][$nid], 4,  t('File usage incremented with files on a new node revision.'));
+
+    // Re-save current revision with file on it once instead of twice. File
+    // usage will be 3.
+    $node = node_load($nid);
+    $node->body[LANGUAGE_NONE][0]['value'] = $this->generateFileMarkup($fid, 1);
+    $saved_vid = $node->vid;
+    node_save($node);
+
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+
+    $this->assertEqual($node->vid, $saved_vid, t('Resaved node revision does not create new revision.'));
+    $this->assertEqual($file_uses['media']['node'][$nid], 3, t('Resaved node revision with fewer files reduces file usage.'));
+
+    // Delete the node. File usage will be 0.
+    $node = node_load($nid);
+    node_delete($nid);
+
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+
+    $this->assertEqual(empty($node), TRUE, t('Node has been deleted.'));
+    $this->assertEqual(empty($file_uses), TRUE, t('Deleting the node removes all file uses.'));
+  }
+
+
+  /**
+   * Tests the behavior of node and file deletion.
+   */
+  public function testFileUsageIncrementingDelete() {
+    // Create a node with file markup in the body field with a new file.
+    $files = $this->drupalGetTestFiles('image');
+    $file = file_save($files[1]);
+    $fid = $file->fid;
+    $file_uses = file_usage_list($file);
+
+    $this->assertEqual(empty($file_uses), TRUE, t('Created a new file with zero uses.'));
+
+    // Create a new node with file markup.
+    $nid = $this->createNode($fid);
+    $file_uses = file_usage_list($file);
+
+    $this->assertEqual($file_uses['media']['node'][$nid], 1, t('Incremented file usage on node save.'));
+
+    // Try to delete the file. file_delete() should return file_usage().
+    $deleted = file_delete($file);
+    $this->assertTrue(is_array($deleted), t('File cannot be deleted while in use by a node.'));
+
+    // Delete the node.
+    node_delete($nid);
+    $node = node_load($nid);
+    $file_uses = file_usage_list($file);
+
+    $this->assertEqual(empty($node), TRUE, t('Node has been deleted.'));
+    $this->assertEqual(empty($file_uses), TRUE, t('File has zero usage after node is deleted.'));
+
+    $deleted = file_delete($file);
+    $this->assertTrue($deleted, t('File can be deleted with no usage.'));
+
+    $file = file_load($fid);
+    $this->assertTrue(empty($file), t('File no longer exists after delete.'));
+  }
+
+}
