You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

432 lines
10 KiB

/*****************************************************************************
* Copyright (C) 2020 Videolabs
*
* Authors: Marvin Scholz <epirat07 at gmail dot com>
* Alexandre Janniaux <ajanni@videolabs.io>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc/vlc.h>
#include <vlc_common.h>
#include <vlc_variables.h>
#include <vlc_plugin.h>
#include <vlc_tick.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <vlc/vlc.h>
#include <vlc_network.h>
#include "vlc_list.h"
#include "libvlc/test.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define TP_PACKET_SIZE 188
#define NUMBER_PACKETS (128)
#define BUFFER_SIZE (TP_PACKET_SIZE*NUMBER_PACKETS)
#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) )
typedef enum
{
INJECT_EOS, /*!< EOS */
// ...TBD.
}
InjectCmdType;
struct media_owner;
static pthread_t read_thread_hnd;
struct media_ctx
{
struct media_owner *owner;
unsigned ref;
const uint8_t *buffer;
size_t available_size;
bool should_flush;
struct vlc_list node;
};
struct media_owner
{
pthread_mutex_t lock;
pthread_cond_t ctx_wait;
pthread_cond_t append_wait;
pthread_cond_t read_wait;
pthread_cond_t flush_wait;
struct vlc_list ctx_list;
bool stopped;
struct media_ctx *active_ctx;
};
static int open_cb(void *opaque, void **datap, uint64_t *sizep)
{
struct media_owner *owner = opaque;
pthread_mutex_lock(&owner->lock);
if (owner->active_ctx != NULL)
{
pthread_mutex_unlock(&owner->lock);
return -1;
}
struct media_ctx *ctx = malloc(sizeof(*ctx));
if (ctx == NULL)
{
pthread_mutex_unlock(&owner->lock);
return -1;
}
ctx->ref = 1;
ctx->owner = owner;
ctx->buffer = NULL;
ctx->available_size = 0;
ctx->should_flush = false;
vlc_list_append(&ctx->node, &owner->ctx_list);
owner->active_ctx = ctx;
pthread_cond_broadcast(&owner->ctx_wait);
*datap = ctx;
*sizep = UINT64_MAX;
pthread_mutex_unlock(&owner->lock);
return 0;
}
static ssize_t read_cb(void *opaque, unsigned char *buf, size_t len)
{
struct media_ctx *ctx = opaque;
pthread_mutex_lock(&ctx->owner->lock);
while (ctx->available_size == 0 && ctx->owner->active_ctx == ctx && !ctx->should_flush)
pthread_cond_wait(&ctx->owner->read_wait, &ctx->owner->lock);
if (ctx->should_flush && ctx->available_size == 0)
{
ctx->should_flush = false;
pthread_cond_broadcast(&ctx->owner->flush_wait);
pthread_mutex_unlock(&ctx->owner->lock);
return 0;
}
if (ctx->owner->active_ctx != ctx)
{
pthread_mutex_unlock(&ctx->owner->lock);
return -1;
}
len = MIN(len, ctx->available_size);
memcpy(buf, ctx->buffer, len);
ctx->buffer += len;
ctx->available_size -= len;
if (ctx->available_size == 0)
pthread_cond_broadcast(&ctx->owner->append_wait);
pthread_mutex_unlock(&ctx->owner->lock);
return len;
}
static int seek_cb(void *opaque, uint64_t offset)
{
return 0;
}
static void close_cb(void *opaque)
{
struct media_ctx *ctx = opaque;
struct media_owner *owner = ctx->owner;
pthread_mutex_lock(&ctx->owner->lock);
if (ctx->owner->active_ctx == ctx)
ctx->owner->active_ctx = NULL;
vlc_list_remove(&ctx->node);
ctx->ref--;
if (ctx->ref == 0)
free(ctx);
pthread_cond_broadcast(&owner->flush_wait);
pthread_mutex_unlock(&owner->lock);
}
static void append_data_locked(struct media_ctx *ctx, const uint8_t *buffer, size_t size)
{
ctx->available_size = size;
ctx->buffer = buffer;
pthread_cond_broadcast(&ctx->owner->read_wait);
while ((ctx->available_size > 0 || ctx->should_flush)
&& ctx->owner->active_ctx == ctx)
pthread_cond_wait(&ctx->owner->append_wait, &ctx->owner->lock);
}
static struct media_ctx *media_owner_lock_active_ctx(struct media_owner *owner)
{
pthread_mutex_lock(&owner->lock);
while (owner->active_ctx == NULL && !owner->stopped)
pthread_cond_wait(&owner->ctx_wait, &owner->lock);
if (owner->active_ctx == NULL)
{
pthread_mutex_unlock(&owner->lock);
return NULL;
}
owner->active_ctx->ref++;
return owner->active_ctx;
}
static void media_owner_unlock_ctx(struct media_owner *owner, struct media_ctx *ctx)
{
ctx->ref--;
if (ctx->ref == 0)
free(ctx);
pthread_mutex_unlock(&owner->lock);
}
static libvlc_instance_t *_libvlc;
static libvlc_media_player_t *_mediaPlayer;
static struct media_owner _media_owner;
static bool _keepLastFrame;
static void init(void)
{
pthread_mutex_init(&_media_owner.lock, NULL);
pthread_cond_init(&_media_owner.ctx_wait, NULL);
pthread_cond_init(&_media_owner.append_wait, NULL);
pthread_cond_init(&_media_owner.read_wait, NULL);
pthread_cond_init(&_media_owner.flush_wait, NULL);
vlc_list_init(&_media_owner.ctx_list);
_media_owner.active_ctx = NULL;
_media_owner.stopped = false;
_keepLastFrame = false;
}
static void destroy(void)
{
pthread_mutex_destroy(&_media_owner.lock);
pthread_cond_destroy(&_media_owner.ctx_wait);
pthread_cond_destroy(&_media_owner.append_wait);
pthread_cond_destroy(&_media_owner.read_wait);
pthread_cond_destroy(&_media_owner.flush_wait);
}
static int start(void)
{
pthread_mutex_lock(&_media_owner.lock);
_media_owner.stopped = false;
pthread_mutex_unlock(&_media_owner.lock);
libvlc_media_t *media =
libvlc_media_new_callbacks(open_cb, read_cb, seek_cb, close_cb,
&_media_owner);
assert(media);
libvlc_media_player_set_media(_mediaPlayer, media);
libvlc_media_release(media);
libvlc_media_player_play(_mediaPlayer);
return 0;
}
static int stop(void)
{
libvlc_media_player_stop_async(_mediaPlayer);
pthread_mutex_lock(&_media_owner.lock);
_media_owner.active_ctx = NULL;
_media_owner.stopped = true;
pthread_cond_broadcast(&_media_owner.ctx_wait);
pthread_cond_broadcast(&_media_owner.append_wait);
pthread_cond_broadcast(&_media_owner.read_wait);
pthread_cond_broadcast(&_media_owner.flush_wait);
pthread_mutex_unlock(&_media_owner.lock);
return 0;
}
static int injectTS(void *bytes, size_t size)
{
struct media_ctx *ctx = media_owner_lock_active_ctx(&_media_owner);
if (ctx == NULL)
return -1;
append_data_locked(ctx, bytes, size);
media_owner_unlock_ctx(&_media_owner, ctx);
return size;
}
static int injectCommand(int command)
{
struct media_ctx *ctx = media_owner_lock_active_ctx(&_media_owner);
if (ctx == NULL)
return -1;
switch (command) {
case INJECT_EOS:
ctx->should_flush = true;
pthread_cond_broadcast(&ctx->owner->read_wait);
break;
default:
media_owner_unlock_ctx(&_media_owner, ctx);
return 1;
}
media_owner_unlock_ctx(&_media_owner, ctx);
return 0;
}
static int clearBuffer(void)
{
libvlc_media_player_set_position(_mediaPlayer, 0, 0);
return 0;
}
static int mpause(void)
{
libvlc_media_player_pause(_mediaPlayer);
return 0;
}
static int resume(void)
{
libvlc_media_player_play(_mediaPlayer);
return 0;
}
static int flushTS(void)
{
struct media_ctx *ctx = media_owner_lock_active_ctx(&_media_owner);
if (ctx == NULL)
return -1;
ctx->should_flush = true;
pthread_cond_broadcast(&ctx->owner->read_wait);
while (ctx->should_flush && _media_owner.active_ctx == ctx)
pthread_cond_wait(&_media_owner.flush_wait, &_media_owner.lock);
media_owner_unlock_ctx(&_media_owner, ctx);
return 0;
}
static const char *file_path = "/home/tom/Downloads/ch15_jtbc_(FHD_H264).ts";
static bool terminate = false;
static void *read_thread(void *data)
{
vlc_object_t *obj = (vlc_object_create)(NULL, sizeof(vlc_object_t));
assert(obj);
char *port_str = getenv("VLCTUNER_PORT");
assert(port_str);
int port = atoi(port_str);
char *addr = getenv("VLCTUNER_ADDR");
assert(addr);
int fd = net_ListenUDP1(obj, addr, port);
assert(fd >= 0);
char readBuffer[BUFFER_SIZE];
unsigned long lastFileOffset = 0;
int dataLength = 0;
int dataSize = 0;
unsigned int written = 0;
while (!terminate)
{
dataLength = (int) read (fd, readBuffer, TP_PACKET_SIZE * NUMBER_PACKETS);
dataSize = dataLength;
if (dataLength > 0)
{
written = injectTS(readBuffer, dataSize);
assert(written > 0);
lastFileOffset += written;
}
}
close(fd);
return NULL;
}
static void lock(void)
{
terminate = false;
int ret = pthread_create(&read_thread_hnd, NULL, read_thread, NULL);
assert(ret == 0);
}
static void unlock(void)
{
terminate = true;
pthread_join(read_thread_hnd, NULL);
}
static long getCurrentSec()
{
return SEC_FROM_VLC_TICK( vlc_tick_now() );
}
int main(int argc, char * argv[])
{
setenv( "VLC_PLUGIN_PATH", "../modules", 1 );
_libvlc = libvlc_new(argc, argv);
assert(_libvlc);
_mediaPlayer = libvlc_media_player_new(_libvlc);
assert(_mediaPlayer);
init();
start();
lock();
while(getchar() != 'q');
unlock();
stop();
}