]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
fsv file formate
authorSeven Du <dujinfang@gmail.com>
Fri, 20 Jul 2012 00:43:05 +0000 (08:43 +0800)
committerSeven Du <dujinfang@gmail.com>
Fri, 20 Jul 2012 03:06:48 +0000 (11:06 +0800)
audio only at this time
video is possible when add a file_write_video interface to core
only tested/working with 8000hz at this time

src/mod/applications/mod_fsv/mod_fsv.c

index 7a798ca1fa37e8813851038e080f6777163c86f9..e3c47cfe768da0b929f9cd82207df16579cfebdd 100644 (file)
  * Contributor(s):
  * 
  * Anthony Minessale II <anthm@freeswitch.org>
+ * Seven Du <dujinfang@gmail.com>
  *
  * mod_fsv -- FS Video File Format
  *
+ *
  */
+
 #include <switch.h>
 
 
@@ -489,13 +492,279 @@ SWITCH_STANDARD_APP(play_fsv_function)
        }
 }
 
+struct fsv_file_context {
+       switch_file_t *fd;
+       char *path;
+       switch_mutex_t *mutex;
+};
+
+typedef struct fsv_file_context fsv_file_context;
+
+static switch_status_t fsv_file_open(switch_file_handle_t *handle, const char *path)
+{
+       fsv_file_context *context;
+       char *ext;
+       unsigned int flags = 0;
+
+       if ((ext = strrchr(path, '.')) == 0) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Format\n");
+               return SWITCH_STATUS_GENERR;
+       }
+       ext++;
+
+       if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) {
+               return SWITCH_STATUS_MEMERR;
+       }
+
+       switch_mutex_init(&context->mutex, SWITCH_MUTEX_NESTED, handle->memory_pool);
+
+       if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
+               flags |= SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE;
+               if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND) || switch_test_flag(handle, SWITCH_FILE_WRITE_OVER)) {
+                       flags |= SWITCH_FOPEN_READ;
+               } else {
+                       flags |= SWITCH_FOPEN_TRUNCATE;
+               }
+
+       }
+
+       if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) {
+               flags |= SWITCH_FOPEN_READ;
+       }
+
+       if (switch_file_open(&context->fd, path, flags, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, handle->memory_pool) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path);
+               return SWITCH_STATUS_GENERR;
+       }
+
+       context->path = switch_core_strdup(handle->memory_pool, path);
+
+       if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) {
+               int64_t samples = 0;
+               switch_file_seek(context->fd, SEEK_END, &samples);
+               handle->pos = samples;
+       }
+
+       handle->samples = 0;
+       handle->samplerate = 8000;
+       handle->channels = 1;
+       handle->format = 0;
+       handle->sections = 0;
+       handle->seekable = 0;
+       handle->speed = 0;
+       handle->pos = 0;
+       handle->private_info = context;
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening File [%s] %dhz\n", path, handle->samplerate);
+
+       if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
+               struct file_header h;
+               size_t len = sizeof(h);
+
+               memset(&h, 0, sizeof(h));
+
+               h.version = VERSION;
+               h.created = switch_micro_time_now();
+
+               switch_set_string(h.video_codec_name, "H264"); /* FIXME: hard coded */
+
+               h.audio_rate = handle->samplerate;
+               h.audio_ptime = 20; /* FIXME: hard coded */
+
+               if (switch_file_write(context->fd, &h, &len) != SWITCH_STATUS_SUCCESS) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File write failed\n");
+                       return SWITCH_STATUS_GENERR;
+               }
+       } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) {
+               struct file_header h;
+               size_t size = sizeof(h);
+
+               if (switch_file_read(context->fd, &h, &size) != SWITCH_STATUS_SUCCESS) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error reading file header\n");
+                       return SWITCH_STATUS_GENERR;
+               }
+
+               if (h.version != VERSION) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "File version does not match!\n");
+                       return SWITCH_STATUS_GENERR;
+               }
+
+               handle->samplerate = h.audio_rate;
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t fsv_file_truncate(switch_file_handle_t *handle, int64_t offset)
+{
+       fsv_file_context *context = handle->private_info;
+       switch_status_t status;
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "truncate file [%s]\n", context->path);
+
+       if ((status = switch_file_trunc(context->fd, offset)) == SWITCH_STATUS_SUCCESS) {
+               handle->pos = 0;
+       }
+
+       return status;
+
+}
+
+static switch_status_t fsv_file_close(switch_file_handle_t *handle)
+{
+       fsv_file_context *context = handle->private_info;
+
+       if (context->fd) {
+               switch_file_close(context->fd);
+               context->fd = NULL;
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t fsv_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence)
+{
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Seek not implemented\n");
+       return SWITCH_STATUS_FALSE;
+}
+
+static switch_status_t fsv_file_read(switch_file_handle_t *handle, void *data, size_t *len)
+{
+       switch_status_t status;
+       size_t need = *len;
+       uint32_t size;
+       size_t bytes = sizeof(size);
+       fsv_file_context *context = handle->private_info;
+
+again:
+
+       status = switch_file_read(context->fd, &size, &bytes);
+
+       if (status != SWITCH_STATUS_SUCCESS) {
+               goto end;
+       }
+
+       if (size & VID_BIT) { /* video */
+               *len = size & ~VID_BIT;
+               /* TODO: read video data */
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "discarding video data %d\n", (int)*len);
+               status = switch_file_read(context->fd, data, len);
+
+               if (status != SWITCH_STATUS_SUCCESS) {
+                       goto end;
+               }
+
+               handle->pos += *len + bytes;
+               goto again;
+       }
+
+       if (size > need) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "size %u > need %u\n", (unsigned int)size, (int)need);
+               goto end;
+       }
+
+       *len = size;
+
+       status = switch_file_read(context->fd, data, len);
+
+       *len /= 2;
+
+end:
+
+       return status;
+}
+
+static switch_status_t fsv_file_write(switch_file_handle_t *handle, void *data, size_t *len)
+{
+       uint32_t datalen = *len * 2;
+       size_t size;
+       switch_status_t status;
+
+       fsv_file_context *context = handle->private_info;
+
+       /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "writing: %ld\n", (long)(*len)); */
+
+       if (*len > 160) { /* when sample rate is 8000 */
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "You are asking to write %d bytes of data which is not supported. Please set enable_file_write_buffering=false to use .fsv format\n", (int)(*len));
+               return SWITCH_STATUS_GENERR;
+       }
+
+       switch_mutex_lock(context->mutex);
+
+       size = sizeof(datalen);
+       if (switch_file_write(context->fd, &datalen, &size) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "write error\n");
+               return SWITCH_STATUS_FALSE;
+       }
+
+       *len = datalen;
+       status =  switch_file_write(context->fd, data, len);
+       switch_mutex_unlock(context->mutex);
+
+       return status;
+}
+
+// static switch_status_t fsv_file_write_video(switch_file_handle_t *handle, void *data, size_t *len)
+// {
+//     uint32_t datalen = *len;
+//     uint32_t bytes = datalen | VID_BIT;
+//     size_t size;
+//     switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+//     fsv_file_context *context = handle->private_info;
+//     /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "writing: %ld\n", (long)(*len)); */
+
+//     switch_mutex_lock(context->mutex);
+
+//     size = sizeof(bytes);
+//     if (switch_file_write(context->fd, &bytes, &size) != SWITCH_STATUS_SUCCESS) {
+//             switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "write error\n");
+//             return SWITCH_STATUS_FALSE;
+//     }
+
+//     *len = datalen;
+//     status =  switch_file_write(context->fd, data, len);
+//     switch_mutex_unlock(context->mutex);
+
+//     return status;
+// }
+
+static switch_status_t fsv_file_set_string(switch_file_handle_t *handle, switch_audio_col_t col, const char *string)
+{
+       return SWITCH_STATUS_FALSE;
+}
+
+static switch_status_t fsv_file_get_string(switch_file_handle_t *handle, switch_audio_col_t col, const char **string)
+{
+       return SWITCH_STATUS_FALSE;
+}
+
+/* Registration */
+
+static char *supported_formats[2] = { 0 };
+
 SWITCH_MODULE_LOAD_FUNCTION(mod_fsv_load)
 {
        switch_application_interface_t *app_interface;
+       switch_file_interface_t *file_interface;
+
+       supported_formats[0] = "fsv";
 
        /* connect my internal structure to the blank pointer passed to me */
        *module_interface = switch_loadable_module_create_module_interface(pool, modname);
 
+       file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
+       file_interface->interface_name = modname;
+       file_interface->extens = supported_formats;
+       file_interface->file_open = fsv_file_open;
+       file_interface->file_close = fsv_file_close;
+       file_interface->file_truncate = fsv_file_truncate;
+       file_interface->file_read = fsv_file_read;
+       file_interface->file_write = fsv_file_write;
+       // file_interface->file_write_video = fsv_file_write_video;
+       file_interface->file_seek = fsv_file_seek;
+       file_interface->file_set_string = fsv_file_set_string;
+       file_interface->file_get_string = fsv_file_get_string;
+
        SWITCH_ADD_APP(app_interface, "play_fsv", "play an fsv file", "play an fsv file", play_fsv_function, "<file>", SAF_NONE);
        SWITCH_ADD_APP(app_interface, "record_fsv", "record an fsv file", "record an fsv file", record_fsv_function, "<file>", SAF_NONE);