Beispiel #1
0
void test_ms_file_scan_1(void)	{
#ifdef WIN32
	char valid_file[MAX_PATH_STR_LEN] = "data\\video\\bars-mpeg4-aac.m4v";
	char invalid_file[MAX_PATH_STR_LEN] = "data\\video\\notafile.m4v";
#else
	char valid_file[MAX_PATH_STR_LEN] = "data/video/bars-mpeg4-aac.m4v";
	char invalid_file[MAX_PATH_STR_LEN] = "data/video/notafile.m4v";
#endif
	MediaScan *s = ms_create();

	CU_ASSERT_FATAL(s != NULL);

	// Check null mediascan oject
	ms_errno = 0;
	ms_scan_file(NULL, invalid_file, TYPE_VIDEO);
	CU_ASSERT(ms_errno == MSENO_NULLSCANOBJ);

	// Check for no callback set
	ms_errno = 0;
	ms_scan_file(s, invalid_file, TYPE_VIDEO);
	CU_ASSERT(ms_errno == MSENO_NORESULTCALLBACK);

	CU_ASSERT(s->on_result == NULL);
	ms_set_result_callback(s, my_result_callback_1);
	CU_ASSERT(s->on_result == my_result_callback_1);

	// Now scan an invalid file, without an error handler
	ms_errno = 0;
	ms_scan_file(s, invalid_file, TYPE_VIDEO);
	CU_ASSERT(ms_errno == MSENO_NOERRORCALLBACK);

	// Set up an error callback
	CU_ASSERT(s->on_error == NULL);
	ms_set_error_callback(s, my_error_callback);
	CU_ASSERT(s->on_error == my_error_callback);

	// Now scan an invalid file, with an error handler
	ms_errno = 0;
	error_called = FALSE;
	ms_scan_file(s, invalid_file, TYPE_VIDEO);
	CU_ASSERT(ms_errno != MSENO_NOERRORCALLBACK);
	CU_ASSERT(error_called == TRUE);

	// Now scan a valid video file, with an error handler
	ms_errno = 0;
	error_called = FALSE;
	ms_scan_file(s, valid_file, TYPE_VIDEO);
	// Need more info to run this test

	ms_destroy(s);
} /* test_ms_file_scan_1 */
Beispiel #2
0
void test_ms_file_asf_audio(void)	{
#ifdef WIN32
	char asf_file[MAX_PATH_STR_LEN] = "data\\audio\\wmv92-with-audio.wmv";
#else
	char asf_file[MAX_PATH_STR_LEN] = "data/audio/wmv92-with-audio.wmv";
#endif
	MediaScan *s = ms_create();

	CU_ASSERT_FATAL(s != NULL);

	CU_ASSERT(s->on_result == NULL);
	ms_set_result_callback(s, my_result_callback_1);
	CU_ASSERT(s->on_result == my_result_callback_1);

	// Set up an error callback
	CU_ASSERT(s->on_error == NULL);
	ms_set_error_callback(s, my_error_callback);
	CU_ASSERT(s->on_error == my_error_callback);

	// Now scan a valid video file, with an error handler
	ms_errno = 0;
	error_called = FALSE;
	ms_scan_file(s, asf_file, TYPE_VIDEO);
	// Need more info to run this test

	ms_destroy(s);
} /* test_ms_file_asf_audio */
void generate_thumbnails()
{
	FILE *tfp;
	char file[MAX_PATH_STR_LEN];
	int i, n;
	MediaScanImage *thumb;
	Buffer *dbuf;

	MediaScan *s = ms_create();
		ms_set_result_callback(s, my_result_callback);
			ms_set_error_callback(s, my_error_callback); 
			
	ms_add_thumbnail_spec(s, THUMB_PNG, 32,32, TRUE, 0, 90);

	for(i = 0; expected_results[i].filename; i++) 
	{
		ms_scan_file(s, expected_results[i].filename, TYPE_IMAGE);

		if (!strcmp("JPEG", result._thumbs[0]->codec))
			sprintf(file, "%s.jpg", expected_results[i].thumb_filename);
		else
			sprintf(file, "%s.png",expected_results[i].thumb_filename);

		write_png_file(file);
	}


		ms_destroy(s);

}
Beispiel #4
0
void test_ms_db(void)	{

#ifdef WIN32
	char valid_file[MAX_PATH_STR_LEN] = "data\\video\\bars-mpeg4-aac.m4v";
#else
	char valid_file[MAX_PATH_STR_LEN] = "data/video/bars-mpeg4-aac.m4v";
#endif

	MediaScan *s = ms_create();

	CU_ASSERT_FATAL(s != NULL);

	CU_ASSERT(s->npaths == 0);

	CU_ASSERT(s->on_result == NULL);
	ms_set_result_callback(s, my_result_callback);
	CU_ASSERT(s->on_result == my_result_callback);

	CU_ASSERT(s->on_error == NULL);
	ms_set_error_callback(s, my_error_callback);
	CU_ASSERT(s->on_error == my_error_callback);

	ms_errno = 0;
	error_called = FALSE;

	// Okay scan a file
	result_called = FALSE;
	ms_scan_file(s, valid_file, TYPE_VIDEO);
	CU_ASSERT(result_called == TRUE);

	// now scan the same file again and make sure it is skipped
	result_called = FALSE;
	ms_scan_file(s, valid_file, TYPE_VIDEO);
	CU_ASSERT(result_called == FALSE);

	// now scan the same file again, this time with a different modification time and make sure it is scanned
	TouchFile(valid_file);
	result_called = FALSE;
	ms_scan_file(s, valid_file, TYPE_VIDEO);
	CU_ASSERT(result_called == TRUE);

	ms_destroy(s);
} /* test_ms_db() */
void test_thumbnailing(void)	{
	int i = 0;

	MediaScan *s = ms_create();

	CU_ASSERT_FATAL(s != NULL);

	CU_ASSERT(s->on_result == NULL);
	ms_set_result_callback(s, my_result_callback);
	CU_ASSERT(s->on_result == my_result_callback);

	CU_ASSERT(s->on_error == NULL);
	ms_set_error_callback(s, my_error_callback); 
	CU_ASSERT(s->on_error == my_error_callback);

	ms_add_thumbnail_spec(s, THUMB_PNG, 32,32, TRUE, 0, 90);

	ms_scan_file(s, expected_results[0].filename, TYPE_IMAGE);

	// TODO: Read and compare presaved and approved thumbnails

	ms_destroy(s);
} /* test_thumbnailing() */
Beispiel #6
0
// Called by ms_scan either in a thread or synchronously
static void *do_scan(void *userdata) {
  MediaScan *s = ((thread_data_type *)userdata)->s;
  int i;
  struct dirq *dir_head = (struct dirq *)s->_dirq;
  struct dirq_entry *dir_entry = NULL;
  struct fileq *file_head = NULL;
  struct fileq_entry *file_entry = NULL;
  char tmp_full_path[MAX_PATH_STR_LEN];

  // Initialize the cache database
  if (!init_bdb(s)) {
    MediaScanError *e = error_create("", MS_ERROR_CACHE, "Unable to initialize libmediascan cache");
    send_error(s, e);
    goto out;
  }

  if (s->flags & MS_CLEARDB) {
    reset_bdb(s);
  }

  if (s->progress == NULL) {
    MediaScanError *e = error_create("", MS_ERROR_TYPE_INVALID_PARAMS, "Progress object not created");
    send_error(s, e);
    goto out;
  }

  // Build a list of all directories and paths
  // We do this first so we can present an accurate scan eta later
  progress_start_phase(s->progress, "Discovering");

  for (i = 0; i < s->npaths; i++) {
    LOG_INFO("Scanning %s\n", s->paths[i]);
    recurse_dir(s, s->paths[i], 0);
  }

  // Scan all files found
  progress_start_phase(s->progress, "Scanning");

  while (!SIMPLEQ_EMPTY(dir_head)) {
    dir_entry = SIMPLEQ_FIRST(dir_head);

    file_head = dir_entry->files;
    while (!SIMPLEQ_EMPTY(file_head)) {
      // check if the scan has been aborted
      if (s->_want_abort) {
        LOG_DEBUG("Aborting scan\n");
        goto aborted;
      }

      file_entry = SIMPLEQ_FIRST(file_head);

      // Construct full path
      strcpy(tmp_full_path, dir_entry->dir);
#ifdef WIN32
      strcat(tmp_full_path, "\\");
#else
      strcat(tmp_full_path, "/");
#endif
      strcat(tmp_full_path, file_entry->file);

      ms_scan_file(s, tmp_full_path, file_entry->type);

      // Send progress update if necessary
      if (s->on_progress) {
        s->progress->done++;

        if (progress_update(s->progress, tmp_full_path))
          send_progress(s);
      }

      SIMPLEQ_REMOVE_HEAD(file_head, entries);
      free(file_entry->file);
      free(file_entry);
    }

    SIMPLEQ_REMOVE_HEAD(dir_head, entries);
    free(dir_entry->dir);
    free(dir_entry->files);
    free(dir_entry);
  }

  // Send final progress callback
  if (s->on_progress) {
    progress_update(s->progress, NULL);
    send_progress(s);
  }

  LOG_DEBUG("Finished scanning\n");

out:
  if (s->on_finish)
    send_finish(s);

aborted:
  if (s->async) {
    LOG_MEM("destroy thread_data @ %p\n", userdata);
    free(userdata);
  }

  return NULL;
}
void WatchDirectory(void *thread_data) {
  // Copy thread inputs to local variables
  MediaScan *s = ((thread_data_type *)thread_data)->s;
  LPTSTR lpDir = ((thread_data_type *)thread_data)->lpDir;

  // Data variables for the windows directory change notification
  OVERLAPPED oOverlap;
  FILE_NOTIFY_INFORMATION Buffer[FILE_BUFFER_SZ];
  char buf[256];
  char full_path[MAX_PATH_STR_LEN];
  DWORD BytesReturned;

  // Overlapped I/O variables
  WSAOVERLAPPED RecvOverlapped;
  HANDLE hDir;
  DWORD dwWaitStatus;
  DWORD dwBytesRead;
  BOOL bResult;
  WSABUF DataBuf;
  DWORD RecvBytes, Flags;
  char buffer[DATA_BUFSIZE];
  int rc = 0;
  int err = 0;
  char *pBase = 0;

  // Thread state variables
  int ThreadRunning = TRUE;

  // Initialize the cache database
  if (!init_bdb(s)) {
    MediaScanError *e = error_create("", MS_ERROR_CACHE, "Unable to initialize libmediascan cache");
    send_error(s, e);
  }

  SecureZeroMemory(buffer, DATA_BUFSIZE);

  // Make sure the RecvOverlapped struct is zeroed out
  SecureZeroMemory((PVOID) & oOverlap, sizeof(OVERLAPPED));

  // Create the event that will get fired when a directory changes
  oOverlap.hEvent = CreateEvent(NULL, // default security attributes
                                TRUE, // manual-reset event
                                FALSE,  // initial state is nonsignaled
                                TEXT("MyFileChangeEvent")); // "FileChangeEvent" name

  // Make sure the RecvOverlapped struct is zeroed out
  SecureZeroMemory((PVOID) & RecvOverlapped, sizeof(WSAOVERLAPPED));

  // Create an event handle and setup an overlapped structure.
  RecvOverlapped.hEvent = WSACreateEvent();
  if (RecvOverlapped.hEvent == NULL) {
    LOG_ERROR("WSACreateEvent failed: %d\n", WSAGetLastError());
    return;
  }

  DataBuf.len = DATA_BUFSIZE;
  DataBuf.buf = buffer;

  // Open the directory that we are going to have windows monitor, note the share modes
  hDir = CreateFile(lpDir,      // pointer to the file name
                    FILE_LIST_DIRECTORY,  // access (read/write) mode
                    FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, // share mode
                    NULL,       // security descriptor
                    OPEN_EXISTING,  // how to create
                    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,  // file attributes
                    NULL);      // file with attributes to copy

  // Tell windows to monitor the folder asyncroniously using overlapped I/O
  ReadDirectoryChangesW(hDir,   // handle to directory
                        &Buffer,  // read results buffer
                        FILE_BUFFER_SZ * sizeof(FILE_NOTIFY_INFORMATION), // length of buffer
                        TRUE,   // Monitor sub-directories = TRUE
                        DETECTION_FILTER, // filter conditions
                        &BytesReturned, // bytes returned
                        &oOverlap,  // We are using overlapped I/O
                        NULL);  // Not using completion routine

  Flags = 0;
/* XXX FIXME, reqpipe is gone
  rc = WSARecv(s->thread->reqpipe[0], &DataBuf, 1, &RecvBytes, &Flags, &RecvOverlapped, NULL);
  if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
    LOG_ERROR("WSARecv failed with error: %d\n", err);
    return;
  }
*/

  // Run until we are told to stop. It is important to let the thread clean up after itself so
  // there is shutdown code at the bottom of this function.
  while (ThreadRunning) {

    // Set up the events are going to wait for
    HANDLE event_list[2] = { oOverlap.hEvent, RecvOverlapped.hEvent };
    FILE_NOTIFY_INFORMATION *fni;
    LOG_LEVEL(1, "\nWaiting for notification...\n");

    // Wait forever for notification.
    dwWaitStatus = WaitForMultipleObjects(2,  // number of objects in array
                                          event_list, // array of objects
                                          FALSE,  // wait for any object
                                          INFINITE);  // infinite wait

    switch (dwWaitStatus) {
        // This is for the event oOverlap.hEvent
      case WAIT_OBJECT_0:
        bResult = GetOverlappedResult(hDir, &oOverlap, &dwBytesRead, TRUE);

        pBase = (char *)Buffer;
        do {

          fni = (FILE_NOTIFY_INFORMATION *) pBase;

          // Note pRecord->FileName is in UTF-16, have to convert it to 8 bits
          WideCharToMultiByte(CP_UTF8, 0, fni->FileName,  // the string you have
                              fni->FileNameLength / 2,  // length of the string
                              buf,  // output
                              _countof(buf),  // size of the buffer in bytes - if you leave it zero the return value is the length required for the output buffer
                              NULL, NULL);
          buf[fni->FileNameLength / 2] = 0;


          // Set up a full path to the file to be scanned and call ms_scan_fileCall scan here with the file changed
          strcpy(full_path, lpDir);
          strcat(full_path, "\\");
          strcat(full_path, buf);
          LOG_INFO("Found File Changed: %s", full_path);

          switch (fni->Action) {

            case FILE_ACTION_ADDED:
              LOG_INFO("  file was added\n");

              // We get notifications even while a file is being copied. This will wait 60 seconds for the file to finish.
              if (WaitForFile(full_path, 10)) {
                ms_scan_file(s, full_path, TYPE_UNKNOWN);
              }
              else {
                LOG_ERROR("A file found by the background scanner never finished copying");
              }

              break;
            case FILE_ACTION_REMOVED:
              LOG_INFO("  file was removed\n");
              HandleRemovedFile(s, full_path);
              break;

            case FILE_ACTION_MODIFIED:
              LOG_INFO("	file was modified\n");  // This can be a change in the time stamp or attributes.";
              // We get notifications even while a file is being copied. This will wait 60 seconds for the file to finish.
              if (WaitForFile(full_path, 10)) {
                ms_scan_file(s, full_path, TYPE_UNKNOWN);
              }
              else {
                LOG_ERROR("A file found by the background scanner never finished copying");
              }

              break;
/*            case FILE_ACTION_RENAMED_OLD_NAME:
								LOG_INFO("	file was renamed and this is the old name\n");
              break;
            case FILE_ACTION_RENAMED_NEW_NAME:
								LOG_INFO("	file was renamed and this is the new name\n");
              break;
*/ }

          if (!fni->NextEntryOffset)
            break;
          pBase += fni->NextEntryOffset;
        } while (TRUE);

        SecureZeroMemory((PVOID) Buffer, sizeof(Buffer));
        ReadDirectoryChangesW(hDir, // handle to directory
                              &Buffer,  // read results buffer
                              sizeof(Buffer), // length of buffer
                              TRUE, // Monitor sub-directories = TRUE
                              DETECTION_FILTER, // filter conditions
                              &BytesReturned, // bytes returned
                              &oOverlap,  // We are using overlapped I/O
                              NULL);  // Not using completion routine

        break;                  /* WAIT_OBJECT_0: */

        // This is for the event s->ghSignalEvent
      case WAIT_OBJECT_0 + 1:

        ThreadRunning = FALSE;

        break;                  /* WAIT_OBJECT_0 + 1: */

      case WAIT_TIMEOUT:

        // A timeout occurred, this would happen if some value other
        // than INFINITE is used in the Wait call and no changes occur.
        // In a single-threaded environment you might not want an
        // INFINITE wait.

        LOG_INFO("\nNo changes in the timeout period.\n");
        break;

      default:
        LOG_ERROR("\n ERROR: Unhandled dwWaitStatus.\n");
        ExitThread(GetLastError());
        break;
    }
  }

  // Free the data that was passed to this thread on the heap
  if (thread_data != NULL) {
    free(thread_data);
    thread_data = NULL;         // Ensure address is not reused.
  }

  CancelIo(hDir);

  if (!HasOverlappedIoCompleted(&oOverlap)) {
    SleepEx(5, TRUE);
  }

  WSACloseEvent(RecvOverlapped.hEvent);
  CloseHandle(oOverlap.hEvent);


  ExitThread(GetLastError());

}                               /* WatchDirectory() */
void test_image_reading(void)	{
	int i = 0;

	MediaScan *s = ms_create();

	CU_ASSERT_FATAL(s != NULL);

	CU_ASSERT(s->on_result == NULL);
	ms_set_result_callback(s, my_result_callback);
	CU_ASSERT(s->on_result == my_result_callback);

	CU_ASSERT(s->on_error == NULL);
	ms_set_error_callback(s, my_error_callback); 
	CU_ASSERT(s->on_error == my_error_callback);

	for(i = 0; expected_results[i].filename; i++) 
	{
		error_called = FALSE;
		result_called = FALSE;

		ms_scan_file(s, expected_results[i].filename, TYPE_IMAGE);
	
		if(expected_results[i].failure) {
			CU_ASSERT(error_called);
			continue;
		}
		else {
			CU_ASSERT(result_called);
		}

		CU_ASSERT_PTR_NOT_NULL(result.mime_type);
		if(result.mime_type) {
			CU_ASSERT_STRING_EQUAL(result.mime_type, expected_results[i].mime_type); }

		CU_ASSERT_PTR_NOT_NULL(result.image);
		if(result.image) {
			CU_ASSERT_STRING_EQUAL(result.image->codec, expected_results[i].codec);
			CU_ASSERT(result.image->width == expected_results[i].width);
			CU_ASSERT(result.image->height == expected_results[i].height);
			CU_ASSERT(result.image->channels == expected_results[i].channels);

			if(!strcmp(expected_results[i].codec, "GIF") )
			{
				CU_ASSERT(result.image->_jpeg == NULL);
				CU_ASSERT(result.image->_png == NULL);
				CU_ASSERT(result.image->_bmp == NULL);
		//		CU_ASSERT(result.image->_gif != NULL);
			}
			else if(!strcmp(expected_results[i].codec, "JPEG") )
			{
				CU_ASSERT(result.image->_jpeg != NULL);
				CU_ASSERT(result.image->_png == NULL);
				CU_ASSERT(result.image->_bmp == NULL);
		//		CU_ASSERT(result.image->_gif == NULL);
			}
			else if(!strcmp(expected_results[i].codec, "PNG") )
			{
				CU_ASSERT(result.image->_jpeg == NULL);
				CU_ASSERT(result.image->_png != NULL);
				CU_ASSERT(result.image->_bmp == NULL);
		//		CU_ASSERT(result.image->_gif == NULL);
			}
			else if(!strcmp(expected_results[i].codec, "BMP") )
			{
				CU_ASSERT(result.image->_jpeg == NULL);
				CU_ASSERT(result.image->_png == NULL);
				CU_ASSERT(result.image->_bmp != NULL);
		//		CU_ASSERT(result.image->_gif == NULL);
			}
		}

	}

	ms_destroy(s);
} /* test_image_reading() */