fsv file formate
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
This commit is contained in:
parent
52bf168b56
commit
30c009b30e
|
@ -24,10 +24,13 @@
|
|||
* 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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue