Files
libstb-hal/raspi/codec.c
2013-10-20 01:04:40 +02:00

268 lines
6.0 KiB
C

/*
* this code is originally from
* pidvbip - tvheadend client for the Raspberry Pi
* (C) Dave Chapman 2012-2013
*
* adaption for libstb-hal
* (C) Stefan Seyfried 2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* codec.c -- audio / video codec queue functions
*/
#include "config.h"
#include <stdio.h>
#include <pthread.h>
#include "codec.h"
void codec_queue_init(struct codec_t* codec)
{
codec->queue_head = NULL;
codec->queue_tail = NULL;
codec->queue_count = 0;
codec->is_running = 1;
codec->PTS = -1;
pthread_mutex_init(&codec->queue_mutex,NULL);
pthread_cond_init(&codec->queue_count_cv,NULL);
pthread_cond_init(&codec->resume_cv,NULL);
pthread_mutex_init(&codec->PTS_mutex,NULL);
pthread_mutex_init(&codec->isrunning_mutex,NULL);
}
int codec_is_running(struct codec_t* codec)
{
int res;
pthread_mutex_lock(&codec->isrunning_mutex);
res = codec->is_running;
pthread_mutex_unlock(&codec->isrunning_mutex);
return res;
}
void codec_flush_queue(struct codec_t* codec)
{
/* Empty the queue */
pthread_mutex_lock(&codec->queue_mutex);
struct codec_queue_t* p = codec->queue_head;
while (p) {
struct codec_queue_t* tmp = p;
p = p->next;
codec_queue_free_item(codec,tmp);
}
codec->queue_count = 0;
codec->queue_head = NULL;
codec->queue_tail = NULL;
pthread_mutex_unlock(&codec->queue_mutex);
}
static void codec_stop0(struct codec_t* codec, int msg)
{
struct codec_queue_t* new = malloc(sizeof(struct codec_queue_t));
if (new == NULL) {
fprintf(stderr,"FATAL ERROR: out of memory adding to queue\n");
exit(1);
}
pthread_mutex_lock(&codec->queue_mutex);
pthread_mutex_lock(&codec->isrunning_mutex);
codec->is_running = 0;
pthread_mutex_unlock(&codec->isrunning_mutex);
/* Empty the queue */
struct codec_queue_t* p = codec->queue_head;
while (p) {
struct codec_queue_t* tmp = p;
p = p->next;
codec_queue_free_item(codec,tmp);
}
new->msgtype = msg;
new->data = NULL;
new->next = NULL;
new->prev = NULL;
codec->queue_head = new;
codec->queue_tail = new;
if (codec->queue_count == 0) {
pthread_cond_signal(&codec->queue_count_cv);
}
codec->queue_count=1;
codec_set_pts(codec,-1);
pthread_mutex_unlock(&codec->queue_mutex);
}
void codec_stop(struct codec_t* codec)
{
codec_stop0(codec, MSG_STOP);
}
void codec_new_channel(struct codec_t* codec)
{
codec_stop0(codec, MSG_NEW_CHANNEL);
}
void codec_send_message(struct codec_t* codec, int m, void* data)
{
struct codec_queue_t* new = malloc(sizeof(struct codec_queue_t));
if (new == NULL) {
fprintf(stderr,"FATAL ERROR: out of memory adding to queue\n");
exit(1);
}
new->msgtype = m;
new->data = data;
pthread_mutex_lock(&codec->queue_mutex);
/* End to end of queue */
if (codec->queue_tail == NULL) {
new->next = NULL;
new->prev = NULL;
codec->queue_head = new;
codec->queue_tail = new;
pthread_cond_signal(&codec->queue_count_cv);
} else {
new->next = NULL;
new->prev = codec->queue_tail;
new->prev->next = new;
codec->queue_tail = new;
}
codec->queue_count++;
pthread_mutex_unlock(&codec->queue_mutex);
}
void codec_pause(struct codec_t* codec)
{
codec_send_message(codec, MSG_PAUSE, NULL);
}
void codec_resume(struct codec_t* codec)
{
pthread_cond_signal(&codec->resume_cv);
}
void codec_queue_add_item(struct codec_t* codec, struct packet_t* packet, int msgtype)
{
if (packet == NULL) {
fprintf(stderr,"ERROR: Adding NULL packet to queue, skipping\n");
return;
}
struct codec_queue_t* new = malloc(sizeof(struct codec_queue_t));
if (new == NULL) {
fprintf(stderr,"FATAL ERROR: out of memory adding to queue\n");
exit(1);
}
new->msgtype = msgtype;
new->data = packet;
pthread_mutex_lock(&codec->queue_mutex);
if (codec->is_running) {
if (codec->queue_head == NULL) {
new->next = NULL;
new->prev = NULL;
codec->queue_head = new;
codec->queue_tail = new;
pthread_cond_signal(&codec->queue_count_cv);
} else {
new->next = codec->queue_head;
new->prev = NULL;
new->next->prev = new;
codec->queue_head = new;
}
codec->queue_count++;
} else {
// fprintf(stderr,"Dropping packet - codec is stopped.\n");
free(packet->buf);
free(packet);
free(new);
}
pthread_mutex_unlock(&codec->queue_mutex);
}
void codec_queue_free_item(__attribute__((unused))struct codec_t* codec, struct codec_queue_t* item)
{
if (item == NULL)
return;
if (item->data) {
free(item->data->buf);
free(item->data);
}
free(item);
}
struct codec_queue_t* codec_queue_get_next_item(struct codec_t* codec)
{
struct codec_queue_t* item;
pthread_mutex_lock(&codec->queue_mutex);
while (codec->queue_tail == NULL)
pthread_cond_wait(&codec->queue_count_cv,&codec->queue_mutex);
item = codec->queue_tail;
codec->queue_tail = codec->queue_tail->prev;
if (codec->queue_tail == NULL) {
codec->queue_head = NULL;
} else {
codec->queue_tail->next = NULL;
}
codec->queue_count--;
pthread_mutex_unlock(&codec->queue_mutex);
return item;
}
void codec_set_pts(struct codec_t* codec, int64_t PTS)
{
pthread_mutex_lock(&codec->PTS_mutex);
codec->PTS = PTS;
pthread_mutex_unlock(&codec->PTS_mutex);
}
int64_t codec_get_pts(struct codec_t* codec)
{
int64_t PTS;
pthread_mutex_lock(&codec->PTS_mutex);
PTS = codec->PTS;
pthread_mutex_unlock(&codec->PTS_mutex);
return PTS;
}