2021-11-30 21:29:18 -06:00
|
|
|
#include "datastream.h"
|
|
|
|
|
2022-02-06 10:14:57 -06:00
|
|
|
#include "render.h"
|
2021-11-30 21:29:18 -06:00
|
|
|
#include "config.h"
|
|
|
|
#include "shader.h"
|
|
|
|
#include "resources.h"
|
2022-02-06 10:14:57 -06:00
|
|
|
#include "sound.h"
|
2021-11-30 21:29:18 -06:00
|
|
|
#include <stdbool.h>
|
2022-02-06 10:14:57 -06:00
|
|
|
#include "log.h"
|
2022-07-02 03:40:50 -05:00
|
|
|
#include "texture.h"
|
2022-07-03 00:43:42 -05:00
|
|
|
#include <stdlib.h>
|
2021-11-30 21:29:18 -06:00
|
|
|
|
2022-06-27 15:16:16 -05:00
|
|
|
struct mShader *vid_shader;
|
|
|
|
|
2022-07-02 03:40:50 -05:00
|
|
|
static void ds_update_texture(uint32_t unit, uint32_t texture, plm_plane_t * plane)
|
2021-11-30 21:29:18 -06:00
|
|
|
{
|
|
|
|
glActiveTexture(unit);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
2022-07-02 03:40:50 -05:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, plane->width, plane->height, 0, GL_RED, GL_UNSIGNED_BYTE, plane->data);
|
2021-11-30 21:29:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static void render_frame(plm_t * mpeg, plm_frame_t * frame, void *user)
|
|
|
|
{
|
|
|
|
struct datastream *ds = user;
|
|
|
|
shader_use(ds->shader);
|
|
|
|
ds_update_texture(GL_TEXTURE0, ds->texture_y, &frame->y);
|
|
|
|
ds_update_texture(GL_TEXTURE1, ds->texture_cb, &frame->cb);
|
|
|
|
ds_update_texture(GL_TEXTURE2, ds->texture_cr, &frame->cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void render_audio(plm_t * mpeg, plm_samples_t * samples, void *user)
|
|
|
|
{
|
2022-07-02 03:40:50 -05:00
|
|
|
struct datastream *ds = user;
|
2022-07-03 00:43:42 -05:00
|
|
|
play_raw(ds->audio_device, samples->interleaved, samples->count * 2);
|
2021-11-30 21:29:18 -06:00
|
|
|
}
|
|
|
|
|
2022-07-02 03:40:50 -05:00
|
|
|
struct Texture *ds_maketexture(struct datastream *ds)
|
|
|
|
{
|
|
|
|
struct Texture *new = malloc(sizeof(*new));
|
|
|
|
new->id = ds->texture_cb;
|
|
|
|
new->width = 500;
|
|
|
|
new->height = 500;
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
2022-02-06 10:14:57 -06:00
|
|
|
void ds_openvideo(struct datastream *ds, const char *video, const char *adriver)
|
2021-11-30 21:29:18 -06:00
|
|
|
{
|
2022-07-02 03:40:50 -05:00
|
|
|
// ds_stop(ds);
|
2021-11-30 21:29:18 -06:00
|
|
|
char buf[MAXPATH] = {'\0'};
|
2022-07-02 03:40:50 -05:00
|
|
|
sprintf(buf, "%s%s", "video/", video);
|
2021-11-30 21:29:18 -06:00
|
|
|
ds->plm = plm_create_with_filename(buf);
|
|
|
|
|
|
|
|
if (!ds->plm) {
|
2022-02-06 10:14:57 -06:00
|
|
|
YughLog(0, 0, "Couldn't open %s", video);
|
2021-11-30 21:29:18 -06:00
|
|
|
}
|
|
|
|
|
2022-07-03 00:43:42 -05:00
|
|
|
YughLog(0, 0, "Opened %s - framerate: %f, samplerate: %d, audio streams: %i, duration: %f",
|
2021-11-30 21:29:18 -06:00
|
|
|
video,
|
|
|
|
plm_get_framerate(ds->plm),
|
2022-07-03 00:43:42 -05:00
|
|
|
plm_get_samplerate(ds->plm),
|
|
|
|
plm_get_num_audio_streams(ds->plm),
|
|
|
|
plm_get_duration(ds->plm)
|
2021-11-30 21:29:18 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
plm_set_video_decode_callback(ds->plm, render_frame, ds);
|
|
|
|
plm_set_audio_decode_callback(ds->plm, render_audio, ds);
|
|
|
|
plm_set_loop(ds->plm, false);
|
|
|
|
|
|
|
|
plm_set_audio_enabled(ds->plm, true);
|
|
|
|
plm_set_audio_stream(ds->plm, 0);
|
|
|
|
|
|
|
|
// Adjust the audio lead time according to the audio_spec buffer size
|
2022-07-03 19:24:53 -05:00
|
|
|
plm_set_audio_lead_time(ds->plm, 4096/48000);
|
2021-11-30 21:29:18 -06:00
|
|
|
|
|
|
|
ds->playing = true;
|
|
|
|
}
|
|
|
|
|
2022-06-27 15:16:16 -05:00
|
|
|
struct datastream *MakeDatastream()
|
2021-11-30 21:29:18 -06:00
|
|
|
{
|
2022-06-27 15:16:16 -05:00
|
|
|
struct datastream *newds = malloc(sizeof(*newds));
|
|
|
|
if (!vid_shader) vid_shader = MakeShader("videovert.glsl", "videofrag.glsl");
|
|
|
|
|
|
|
|
newds->shader = vid_shader;
|
2021-11-30 21:29:18 -06:00
|
|
|
shader_use(newds->shader);
|
|
|
|
glGenTextures(1, &newds->texture_y);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, newds->texture_y);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
shader_setint(newds->shader, "texture_y", 0);
|
|
|
|
|
|
|
|
glGenTextures(1, &newds->texture_cb);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, newds->texture_cb);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
shader_setint(newds->shader, "texture_cb", 1);
|
|
|
|
|
|
|
|
glGenTextures(1, &newds->texture_cr);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, newds->texture_cr);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
shader_setint(newds->shader, "texture_cr", 2);
|
|
|
|
|
|
|
|
return newds;
|
|
|
|
}
|
|
|
|
|
2022-07-02 03:40:50 -05:00
|
|
|
void ds_advance(struct datastream *ds, double s)
|
2021-11-30 21:29:18 -06:00
|
|
|
{
|
|
|
|
if (ds->playing) {
|
2022-07-02 03:40:50 -05:00
|
|
|
plm_decode(ds->plm, s);
|
2021-11-30 21:29:18 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-02 03:40:50 -05:00
|
|
|
void ds_seek(struct datastream *ds, double time)
|
2021-11-30 21:29:18 -06:00
|
|
|
{
|
2022-02-06 10:14:57 -06:00
|
|
|
clear_raw(ds->audio_device);
|
2021-11-30 21:29:18 -06:00
|
|
|
plm_seek(ds->plm, time, false);
|
|
|
|
}
|
|
|
|
|
2022-01-19 16:43:21 -06:00
|
|
|
void ds_advanceframes(struct datastream *ds, int frames)
|
2021-11-30 21:29:18 -06:00
|
|
|
{
|
|
|
|
for (int i = 0; i < frames; i++) {
|
|
|
|
plm_frame_t *frame = plm_decode_video(ds->plm);
|
|
|
|
render_frame(ds->plm, frame, ds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ds_pause(struct datastream *ds)
|
|
|
|
{
|
|
|
|
ds->playing = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ds_stop(struct datastream *ds)
|
|
|
|
{
|
|
|
|
if (ds->plm != NULL) {
|
|
|
|
plm_destroy(ds->plm);
|
|
|
|
ds->plm = NULL;
|
|
|
|
}
|
|
|
|
if (ds->audio_device)
|
2022-02-06 10:14:57 -06:00
|
|
|
close_audio_device(ds->audio_device);
|
2021-11-30 21:29:18 -06:00
|
|
|
ds->playing = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Must be a better way
|
|
|
|
int ds_videodone(struct datastream *ds)
|
|
|
|
{
|
|
|
|
return (ds->plm == NULL)
|
|
|
|
|| plm_get_time(ds->plm) >= plm_get_duration(ds->plm);
|
|
|
|
}
|
|
|
|
|
|
|
|
double ds_remainingtime(struct datastream *ds)
|
|
|
|
{
|
|
|
|
if (ds->plm != NULL)
|
|
|
|
return plm_get_duration(ds->plm) - plm_get_time(ds->plm);
|
|
|
|
else
|
|
|
|
return 0.f;
|
|
|
|
}
|
2022-01-19 16:43:21 -06:00
|
|
|
|
|
|
|
double ds_length(struct datastream *ds)
|
|
|
|
{
|
|
|
|
return plm_get_duration(ds->plm);
|
2022-02-06 10:14:57 -06:00
|
|
|
}
|