adjust buffer queue

dev
xufuji456 3 years ago
parent 6e52fc3832
commit 4114651e59
  1. 2
      app/CMakeLists.txt
  2. 70
      app/src/main/cpp/visualizer/block_queue.c
  3. 40
      app/src/main/cpp/visualizer/block_queue.h
  4. 42
      app/src/main/cpp/visualizer/execute_fft.c
  5. 19
      app/src/main/cpp/visualizer/execute_fft.h
  6. 154
      app/src/main/cpp/visualizer/queue.c
  7. 258
      app/src/main/cpp/visualizer/vlc_queue.h

@ -35,7 +35,7 @@ add_library( # Sets the name of the library.
src/main/cpp/fast_start.c src/main/cpp/fast_start.c
src/main/cpp/ffprobe_cmd.cpp src/main/cpp/ffprobe_cmd.cpp
src/main/cpp/visualizer/fft.c src/main/cpp/visualizer/fft.c
src/main/cpp/visualizer/queue.c src/main/cpp/visualizer/block_queue.c
src/main/cpp/visualizer/execute_fft.c src/main/cpp/visualizer/execute_fft.c
src/main/cpp/visualizer/window.c src/main/cpp/visualizer/window.c
) )

@ -0,0 +1,70 @@
//
// Created by frank on 2021/08/08.
//
#include "block_queue.h"
#include <stdlib.h>
#include <libavcodec/avcodec.h>
vlc_queue_t *vlc_queue_init(int size) {
vlc_queue_t *queue = (vlc_queue_t *)(malloc(sizeof(vlc_queue_t)));
queue->size = size;
queue->next_to_read = 0;
queue->next_to_write = 0;
int i;
queue->packets = (void **)(malloc(sizeof(*queue->packets) * size));
for (i = 0; i < size; i++) {
queue->packets[i] = malloc(sizeof(AVPacket));
}
pthread_mutex_init(&queue->mutex, NULL);
pthread_cond_init(&queue->cond, NULL);
return queue;
}
void vlc_queue_free(vlc_queue_t *queue) {
int i;
for (i = 0; i < queue->size; i++) {
free(queue->packets[i]);
}
free(queue->packets);
free(queue);
pthread_cond_destroy(&queue->cond);
pthread_mutex_destroy(&queue->mutex);
}
int vlc_queue_next(vlc_queue_t *queue, int current) {
return (current + 1) % queue->size;
}
void *vlc_queue_push(vlc_queue_t *queue, void *data) {
pthread_mutex_lock(&queue->mutex);//lock
int current = queue->next_to_write;
int next_to_write;
for (;;) {
next_to_write = vlc_queue_next(queue, current);
if (next_to_write != queue->next_to_read) {
break;
}
pthread_cond_wait(&queue->cond, &queue->mutex);
}
queue->next_to_write = next_to_write;
queue->packets[current] = data;//TODO
pthread_cond_broadcast(&queue->cond);
pthread_mutex_unlock(&queue->mutex);//unlock
return queue->packets[current];
}
void *vlc_queue_pop(vlc_queue_t *queue) {
pthread_mutex_lock(&queue->mutex);
int current = queue->next_to_read;
for (;;) {
if (queue->next_to_write != queue->next_to_read) {
break;
}
pthread_cond_wait(&queue->cond, &queue->mutex);
}
queue->next_to_read = vlc_queue_next(queue, current);
pthread_cond_broadcast(&queue->cond);
pthread_mutex_unlock(&queue->mutex);
return queue->packets[current];
}

@ -0,0 +1,40 @@
//
// Created by frank on 2021/08/08.
//
#ifndef BLOCK_QUEUE_H
#define BLOCK_QUEUE_H
#include <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct vlc_queue {
//the size of queue
int size;
//packet array
void **packets;
//the packet next to write
int next_to_write;
//the packet next to read
int next_to_read;
pthread_mutex_t mutex;
pthread_cond_t cond;
} vlc_queue_t;
vlc_queue_t *vlc_queue_init(int size);
void vlc_queue_free(vlc_queue_t *queue);
void *vlc_queue_push(vlc_queue_t *queue, void *data);
void *vlc_queue_pop(vlc_queue_t *queue);
#endif //BLOCK_QUEUE_H
#ifdef __cplusplus
}
#endif

@ -15,29 +15,6 @@
#define BAR_DECREMENT .075f #define BAR_DECREMENT .075f
#define ROTATION_MAX 20 #define ROTATION_MAX 20
static inline void block_CopyProperties(block_t *dst, const block_t *src)
{
dst->i_dts = src->i_dts;
dst->i_pts = src->i_pts;
dst->i_flags = src->i_flags;
dst->i_length = src->i_length;
dst->i_nb_samples = src->i_nb_samples;
}
static inline block_t *block_Duplicate(const block_t *p_block)
{
// block_t *p_dup = block_Alloc(p_block->i_buffer);//TODO
block_t *p_dup = (block_t*) malloc(sizeof(block_t));
if(p_dup == NULL) return NULL;
p_dup->i_buffer = p_block->i_buffer;
p_dup->p_buffer = (uint8_t*) malloc(p_block->i_buffer);//TODO
block_CopyProperties(p_dup, p_block);
memcpy(p_dup->p_buffer, p_block->p_buffer, p_block->i_buffer);
return p_dup;
}
/*static*/ int open_visualizer(filter_sys_t *p_sys) /*static*/ int open_visualizer(filter_sys_t *p_sys)
{ {
if (p_sys == NULL) if (p_sys == NULL)
@ -58,7 +35,9 @@ static inline block_t *block_Duplicate(const block_t *p_block)
window_get_param(&p_sys->wind_param); window_get_param(&p_sys->wind_param);
/* Create the FIFO for the audio data. */ /* Create the FIFO for the audio data. */
vlc_queue_Init(&p_sys->queue, offsetof (block_t, p_next)); // vlc_queue_Init(&p_sys->queue, offsetof (block_t, p_next));
vlc_queue_t *queue = vlc_queue_init(5);
p_sys->queue = *queue;
p_sys->dead = false; p_sys->dead = false;
/* Create the thread */ /* Create the thread */
@ -74,7 +53,8 @@ static inline block_t *block_Duplicate(const block_t *p_block)
/*static*/ block_t *filter_audio(filter_sys_t *p_sys, block_t *p_in_buf) /*static*/ block_t *filter_audio(filter_sys_t *p_sys, block_t *p_in_buf)
{ {
vlc_queue_Enqueue(&p_sys->queue, block_Duplicate(p_in_buf)); // vlc_queue_Enqueue(&p_sys->queue, block_Duplicate(p_in_buf));
vlc_queue_push(&p_sys->queue, p_in_buf);
return p_in_buf; return p_in_buf;
} }
@ -83,7 +63,7 @@ static inline block_t *block_Duplicate(const block_t *p_block)
filter_sys_t *p_sys = p_filter; filter_sys_t *p_sys = p_filter;
/* Terminate the thread. */ /* Terminate the thread. */
vlc_queue_Kill(&p_sys->queue, &p_sys->dead); vlc_queue_free(&p_sys->queue);
// vlc_join(p_sys->thread, NULL); // vlc_join(p_sys->thread, NULL);
pthread_join(p_sys->thread, NULL); pthread_join(p_sys->thread, NULL);
@ -97,7 +77,8 @@ static void *fft_thread(void *p_data)
float height[NB_BANDS] = {0}; float height[NB_BANDS] = {0};
LOGE("start FFT thread..."); LOGE("start FFT thread...");
while ((block = vlc_queue_DequeueKillable(&p_sys->queue, &p_sys->dead))) // while ((block = vlc_queue_DequeueKillable(&p_sys->queue, &p_sys->dead)))
while ((block = vlc_queue_pop(&p_sys->queue)))
{ {
LOGE("running FFT transform..."); LOGE("running FFT transform...");
unsigned win_width, win_height; unsigned win_width, win_height;
@ -218,15 +199,14 @@ static void *fft_thread(void *p_data)
/* Wait to swapp the frame on time. */ /* Wait to swapp the frame on time. */
// vlc_tick_wait(block->i_pts + (block->i_length / 2)); // vlc_tick_wait(block->i_pts + (block->i_length / 2));
// vlc_gl_Swap(gl); // vlc_gl_Swap(gl);
usleep(block->i_pts + (block->i_length / 2)); usleep(200*1000 /*block->i_pts + (block->i_length / 2)*/);
LOGE("height[0]=%f, height[1]=%f, height=[2]=%f", height[0], height[1], height[2]); LOGE("height[0]=%f, height[1]=%f, height=[2]=%f", height[0], height[1], height[2]);
release: release:
window_close(&wind_ctx); window_close(&wind_ctx);
fft_close(p_state); fft_close(p_state);
// block_Release(block);//TODO // if (block->p_buffer) free(block->p_buffer);
if (block->p_buffer) free(block->p_buffer); // free(block);
free(block);
} }
return NULL; return NULL;

@ -2,10 +2,10 @@
// Created by frank on 2021/8/16. // Created by frank on 2021/8/16.
// //
#ifndef EXECUTE_FFT_H #ifndef PLAYER_CORE_RUN_FFT_H
#define EXECUTE_FFT_H #define PLAYER_CORE_RUN_FFT_H
#include "vlc_queue.h" #include "block_queue.h"
#include "fft.h" #include "fft.h"
#include "window.h" #include "window.h"
@ -23,28 +23,17 @@ typedef int64_t vlc_tick_t;
typedef struct block_t block_t; typedef struct block_t block_t;
struct vlc_block_callbacks
{
void (*free)(block_t *);
};
struct block_t struct block_t
{ {
block_t *p_next; block_t *p_next;
uint8_t *p_buffer; /**< Payload start */ uint8_t *p_buffer; /**< Payload start */
size_t i_buffer; /**< Payload length */ size_t i_buffer; /**< Payload length */
uint8_t *p_start; /**< Buffer start */
size_t i_size; /**< Buffer total size */
uint32_t i_flags;
unsigned i_nb_samples; /* Used for audio */ unsigned i_nb_samples; /* Used for audio */
vlc_tick_t i_pts; vlc_tick_t i_pts;
vlc_tick_t i_dts;
vlc_tick_t i_length; vlc_tick_t i_length;
const struct vlc_block_callbacks *cbs;
}; };
typedef struct typedef struct
@ -73,4 +62,4 @@ static void *fft_thread(void *);
/*static*/ void close_visualizer(filter_sys_t *p_filter); /*static*/ void close_visualizer(filter_sys_t *p_filter);
#endif //EXECUTE_FFT_H #endif //PLAYER_CORE_RUN_FFT_H

@ -1,154 +0,0 @@
/*****************************************************************************
* queue.c: generic queue (FIFO)
*****************************************************************************
* Copyright (C) 2020 Rémi Denis-Courmont
*
* 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.
*****************************************************************************/
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "vlc_queue.h"
/* Opaque struct type.
*
* ISO C uses the same representation for all pointer-to-struct types.
* Still different pointer types are not compatible, i.e. cannot alias.
* So use memcpy() to read/write pointer values.
*/
struct vlc_queue_entry;
static void entry_set(struct vlc_queue_entry **pp, struct vlc_queue_entry *e)
{
memcpy(pp, &e, sizeof (e));
}
static struct vlc_queue_entry *entry_get(struct vlc_queue_entry *const *pp)
{
struct vlc_queue_entry *e;
memcpy(&e, pp, sizeof (e));
return e;
}
static struct vlc_queue_entry **next_p(const struct vlc_queue_entry *e,
ptrdiff_t offset)
{
return (struct vlc_queue_entry **)(((unsigned char *)e) + offset);
}
static void next_set(struct vlc_queue_entry *e, struct vlc_queue_entry *next,
ptrdiff_t offset)
{
entry_set(next_p(e, offset), next);
}
static struct vlc_queue_entry *next_get(const struct vlc_queue_entry *e,
ptrdiff_t offset)
{
return entry_get(next_p(e, offset));
}
void vlc_queue_Init(vlc_queue_t *q, ptrdiff_t next_offset)
{
q->first = NULL;
q->lastp = &q->first;
q->next_offset = next_offset;
pthread_mutex_init(&q->lock, NULL);
pthread_cond_init(&q->wait, NULL);
}
void vlc_queue_EnqueueUnlocked(vlc_queue_t *q, void *entry)
{
struct vlc_queue_entry **lastp;
const ptrdiff_t offset = q->next_offset;
// vlc_mutex_assert(&q->lock);
assert(entry_get(q->lastp) == NULL);
entry_set(q->lastp, entry);
for (lastp = q->lastp; entry != NULL; entry = next_get(entry, offset))
lastp = next_p(entry, offset);
q->lastp = lastp;
vlc_queue_Signal(q);
}
void *vlc_queue_DequeueUnlocked(vlc_queue_t *q)
{
// vlc_mutex_assert(&q->lock);
void *entry = q->first;
const ptrdiff_t offset = q->next_offset;
if (entry != NULL) {
struct vlc_queue_entry *next = next_get(entry, offset);
next_set(entry, NULL, offset);
q->first = next;
if (next == NULL)
q->lastp = &q->first;
}
return entry;
}
void *vlc_queue_DequeueAllUnlocked(vlc_queue_t *q)
{
// vlc_mutex_assert(&q->lock);
void *entry = q->first;
q->first = NULL;
q->lastp = &q->first;
return entry;
}
void vlc_queue_Enqueue(vlc_queue_t *q, void *entry)
{
vlc_queue_Lock(q);
vlc_queue_EnqueueUnlocked(q, entry);
vlc_queue_Unlock(q);
}
void *vlc_queue_Dequeue(vlc_queue_t *q)
{
void *entry;
vlc_queue_Lock(q);
while (vlc_queue_IsEmpty(q))
vlc_queue_Wait(q);
entry = vlc_queue_DequeueUnlocked(q);
vlc_queue_Unlock(q);
return entry;
}
void *vlc_queue_DequeueAll(vlc_queue_t *q)
{
void *entry;
vlc_queue_Lock(q);
entry = vlc_queue_DequeueAllUnlocked(q);
vlc_queue_Unlock(q);
return entry;
}

@ -1,258 +0,0 @@
/*****************************************************************************
* vlc_queue.h: generic queue functions
*****************************************************************************
* Copyright (C) 2020 Rémi Denis-Courmont
*
* 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.
*****************************************************************************/
#ifndef VLC_QUEUE_H
#define VLC_QUEUE_H
/**
* @defgroup queue Thread-safe queues (FIFO)
* @ingroup cext
* @{
* @file vlc_queue.h
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
/**
* Opaque type for queue entry.
*/
struct vlc_queue_entry;
/**
* Thread-safe queue (a.k.a. FIFO).
*/
typedef struct vlc_queue
{
struct vlc_queue_entry *first;
struct vlc_queue_entry **lastp;
ptrdiff_t next_offset;
pthread_mutex_t lock;
pthread_cond_t wait;
} vlc_queue_t;
/**
* Initializes a queue.
*
* @param queue storage space for the queue
* @param next_offset offset of the pointer to the next element
* within a queue entry (as per @c offsetof())
*/
void vlc_queue_Init(vlc_queue_t *queue, ptrdiff_t next_offset);
/**
* @defgroup queue_ll Queue internals
*
* Low-level queue functions.
*
* In some cases, the high-level queue functions do not exactly fit the
* use case requirements, and it is necessary to access the queue internals.
* This typically occurs when threads wait for elements to be added to the
* queue at the same time as some other type of events.
* @{
*/
/**
* Locks a queue.
*
* No more than one thread can lock a queue at any given time, and no other
* thread can modify the queue while it is locked.
* Accordingly, if the queue is already locked by another thread, this function
* waits.
*
* Use vlc_queue_Unlock() to release the lock.
*
* @warning Recursively locking a single queue is undefined.
* Also locking more than one queue at a time may lead to lock inversion:
* mind the locking order!
*/
static inline void vlc_queue_Lock(vlc_queue_t *q)
{
pthread_mutex_lock(&q->lock);
}
/**
* Unlocks a queue.
*
* This releases the lock on a queue, allowing other threads to manipulate the
* queue. The behaviour is undefined if the calling thread is not holding the
* queue lock.
*/
static inline void vlc_queue_Unlock(vlc_queue_t *q)
{
pthread_mutex_unlock(&q->lock);
}
/**
* Wakes one thread waiting for a queue entry up.
*/
static inline void vlc_queue_Signal(vlc_queue_t *q)
{
pthread_cond_signal(&q->wait);
}
/**
* Waits for a queue entry.
*
* @note This function is a cancellation point.
* In case of cancellation, the queue will be locked,
* as is consistent for condition variable semantics.
*
* @bug This function should probably not be aware of cancellation.
*/
static inline void vlc_queue_Wait(vlc_queue_t *q)
{
pthread_cond_wait(&q->wait, &q->lock);
}
/**
* Queues an entry (without locking).
*
* This function enqueues an entry, or rather a linked-list of entries, in a
* thread-safe queue, without taking the queue lock.
*
* @warning It is assumed that the caller already holds the queue lock;
* otherwise the behaviour is undefined.
*
* @param entry NULL-terminated list of entries to queue
* (if NULL, this function has no effects)
*/
void vlc_queue_EnqueueUnlocked(vlc_queue_t *, void *entry);
/**
* Dequeues the oldest entry (without locking).
*
* This function dequeues an entry from a thread-safe queue. It is assumed
* that the caller already holds the queue lock; otherwise the behaviour is
* undefined.
*
* @warning It is assumed that the caller already holds the queue lock;
* otherwise the behaviour is undefined.
*
* @return the first entry in the queue, or NULL if the queue is empty
*/
void *vlc_queue_DequeueUnlocked(vlc_queue_t *);
/**
* Dequeues all entries (without locking).
*
* This is equivalent to calling vlc_queue_DequeueUnlocked() repeatedly until
* the queue is emptied. However this function is much faster than that, as it
* does not need to update the linked-list pointers.
*
* @warning It is assumed that the caller already holds the queue lock;
* otherwise the behaviour is undefined.
*
* @return a linked-list of all entries (possibly NULL if none)
*/
void *vlc_queue_DequeueAllUnlocked(vlc_queue_t *);
/**
* Checks if a queue is empty (without locking).
*
* @warning It is assumed that the caller already holds the queue lock;
* otherwise the behaviour is undefined.
*
* @retval false the queue contains one or more entries
* @retval true the queue is empty
*/
static inline bool vlc_queue_IsEmpty(const vlc_queue_t *q)
{
return q->first == NULL;
}
/** @} */
/**
* Queues an entry.
*
* This function enqueues an entry, or rather a linked-list of entries, in a
* thread-safe queue.
*
* @param entry list of entries (if NULL, this function has no effects)
*/
void vlc_queue_Enqueue(vlc_queue_t *, void *entry);
/**
* Dequeues the oldest entry.
*
* This function dequeues an entry from a thread-safe queue. If the queue is
* empty, it will wait until at least one entry is available.
*
* @param offset offset of the next pointer within a queue entry
*
* @return the first entry in the queue, or NULL if the queue is empty
*/
void *vlc_queue_Dequeue(vlc_queue_t *);
/**
* Dequeues all entries.
*
* This is equivalent to calling vlc_queue_Dequeue() repeatedly until the queue
* is emptied. However this function is much faster than that, as it
* does not need to update the linked-list pointers.
*
* @return a linked-list of all entries (possibly NULL if none)
*/
void *vlc_queue_DequeueAll(vlc_queue_t *);
/**
* @defgroup queue_killable Killable queues
*
* Thread-safe queues with an end flag.
*
* @{
*/
/**
* Marks a queue ended.
*/
static inline void vlc_queue_Kill(vlc_queue_t *q,
bool */*restrict*/ tombstone)
{
vlc_queue_Lock(q);
*tombstone = true;
vlc_queue_Signal(q);
vlc_queue_Unlock(q);
pthread_cond_destroy(&q->wait);
pthread_mutex_destroy(&q->lock);
}
/**
* Dequeues one entry from a killable queue.
*
* @return an entry, or NULL if the queue is empty and has been ended.
*/
static inline void *vlc_queue_DequeueKillable(vlc_queue_t *q,
bool */*restrict*/ tombstone)
{
void *entry;
vlc_queue_Lock(q);
while (vlc_queue_IsEmpty(q) && !*tombstone)
vlc_queue_Wait(q);
entry = vlc_queue_DequeueUnlocked(q);
vlc_queue_Unlock(q);
return entry;
}
#endif
Loading…
Cancel
Save