mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-15 00:34:05 +09:00
update language choice processing
This commit is contained in:
@@ -105,7 +105,6 @@ airplay_video_t *airplay_video_init(raop_t *raop, unsigned short http_port,
|
|||||||
void
|
void
|
||||||
airplay_video_destroy(airplay_video_t *airplay_video)
|
airplay_video_destroy(airplay_video_t *airplay_video)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (airplay_video->uri_prefix) {
|
if (airplay_video->uri_prefix) {
|
||||||
free(airplay_video->uri_prefix);
|
free(airplay_video->uri_prefix);
|
||||||
}
|
}
|
||||||
@@ -118,10 +117,9 @@ airplay_video_destroy(airplay_video_t *airplay_video)
|
|||||||
if (airplay_video->media_data_store) {
|
if (airplay_video->media_data_store) {
|
||||||
destroy_media_data_store(airplay_video);
|
destroy_media_data_store(airplay_video);
|
||||||
}
|
}
|
||||||
if (airplay_video->master_playlist) {
|
if (airplay_video->master_playlist){
|
||||||
free (airplay_video->master_playlist);
|
free (airplay_video->master_playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
free (airplay_video);
|
free (airplay_video);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +176,7 @@ const char *get_language_name(airplay_video_t *airplay_video) {
|
|||||||
return (const char *)airplay_video->language_name;
|
return (const char *)airplay_video->language_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_language_code(airplay_video_t *airplay_video, char *language_code) {
|
void set_language_code(airplay_video_t *airplay_video, char *language_code) {;
|
||||||
if (airplay_video->language_code) {
|
if (airplay_video->language_code) {
|
||||||
free (airplay_video->language_code);
|
free (airplay_video->language_code);
|
||||||
}
|
}
|
||||||
@@ -213,16 +211,17 @@ void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef struct language_s {
|
typedef struct language_s {
|
||||||
char *start;
|
const char *start;
|
||||||
int len;
|
int len;
|
||||||
char type;
|
bool is_default;
|
||||||
char code[6];
|
char code[6];
|
||||||
|
char *name;
|
||||||
} language_t;
|
} language_t;
|
||||||
|
|
||||||
language_t* master_playlist_process_language(char * data, int *slices, int *language_count) {
|
language_t* master_playlist_process_language(const char * data, int *slices, int *language_count) {
|
||||||
*language_count = 0;
|
*language_count = 0;
|
||||||
char *ptr = data;
|
const char *ptr = data;
|
||||||
int count = 0, count1 = 0, count2 = 0, count3 = 0;
|
int count = 0, count1 = 0;
|
||||||
while (ptr) {
|
while (ptr) {
|
||||||
ptr = strstr(ptr,"#EXT-X-MEDIA:URI=");
|
ptr = strstr(ptr,"#EXT-X-MEDIA:URI=");
|
||||||
if(!ptr) {
|
if(!ptr) {
|
||||||
@@ -242,76 +241,80 @@ language_t* master_playlist_process_language(char * data, int *slices, int *lang
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
language_t *languages = (language_t *) calloc(count + 2, sizeof(language_t));
|
language_t *languages = (language_t *) calloc(count + 2, sizeof(language_t));
|
||||||
languages[0].start = data;
|
size_t length = 0;
|
||||||
ptr = data;
|
ptr = data;
|
||||||
for (int i = 1; i <= count; i++) {
|
for (int i = 1; i <= count; i++) {
|
||||||
char *end;
|
char *end;
|
||||||
|
int len_name;
|
||||||
if (!(ptr = strstr(ptr, "#EXT-X-MEDIA"))) {
|
if (!(ptr = strstr(ptr, "#EXT-X-MEDIA"))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
count1++;
|
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
languages[0].len = (int) (ptr - data);
|
length = (int) (ptr - data);
|
||||||
languages[0].type = ' ';
|
languages[0].start = data;
|
||||||
|
languages[0].len = length;
|
||||||
|
*languages[0].code = '\0';
|
||||||
|
languages[0].name = NULL;
|
||||||
}
|
}
|
||||||
languages[i].start = ptr;
|
languages[i].start = ptr;
|
||||||
if (!(ptr = strstr(ptr, "LANGUAGE="))) {
|
|
||||||
|
if (!(ptr = strstr(ptr, "DEFAULT="))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!strncmp(ptr - strlen("dubbed-auto") - 2, "dubbed-auto", strlen("dubbed-auto"))) {
|
ptr += strlen("DEFAULT=");
|
||||||
languages[i].type = 'd';
|
languages[i].is_default = !strncmp(ptr, "YES", strlen("YES"));
|
||||||
} else if (!strncmp(ptr - strlen("dubbed") - 2, "dubbed", strlen("dubbed"))) {
|
if (!(ptr = strstr(ptr, "NAME="))) {
|
||||||
languages[i].type = 'd';
|
break;
|
||||||
} else if (!strncmp(ptr - strlen("original") - 2, "original", strlen("original"))) {
|
}
|
||||||
languages[i].type = 'o';
|
ptr += strlen("NAME=");
|
||||||
} else {
|
end = strchr(++ptr,'"');
|
||||||
languages[i].type = 'u';
|
if (!end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len_name = end - ptr;
|
||||||
|
languages[i].name = (char *) calloc(len_name + 1, sizeof(char));
|
||||||
|
memcpy(languages[i].name, ptr, len_name *sizeof(char));
|
||||||
|
if (!(ptr = strstr(ptr, "LANGUAGE="))) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
count2++;
|
|
||||||
if (!(ptr = strchr(ptr,'"'))) {
|
if (!(ptr = strchr(ptr,'"'))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ptr++;
|
if (!(end = strchr(++ptr,'"'))) {
|
||||||
if (!(end = strchr(ptr,'"'))) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
strncpy(languages[i].code, ptr, end - ptr);
|
strncpy(languages[i].code, ptr, end - ptr);
|
||||||
if (!(ptr = strchr(ptr,'\n'))) {
|
if (!(ptr = strchr(ptr,'\n'))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
count3++;
|
count1++;
|
||||||
languages[i].len = (int) (ptr + 1 - languages[i].start);
|
languages[i].len = (int) (ptr + 1 - languages[i].start);
|
||||||
|
length += languages[i].len;
|
||||||
}
|
}
|
||||||
assert (count1 == count && count2 == count && count3 == count);
|
assert (count1 == count);
|
||||||
|
|
||||||
languages[count + 1].start = ++ptr;
|
languages[count + 1].start = ++ptr;
|
||||||
languages[count + 1].len = strlen(ptr);
|
languages[count + 1].len = strlen(ptr);
|
||||||
languages[count + 1].type = ' ';
|
*languages[count + 1].code = '\0';
|
||||||
|
languages[count + 1].name = NULL;
|
||||||
|
|
||||||
|
length += languages[count + 1].len;
|
||||||
|
assert(length == strlen(data));
|
||||||
*slices = count + 2;
|
*slices = count + 2;
|
||||||
int len = 0;
|
|
||||||
int copies = 0;
|
int copies = 0;
|
||||||
for (int i = 0; i < *slices; i++) {
|
for (int i = 1; i < count; i++) {
|
||||||
if (!strcmp(languages[i].code, languages[1].code)) {
|
if (!strcmp(languages[i].code, languages[1].code)) {
|
||||||
copies++;
|
copies++;
|
||||||
}
|
}
|
||||||
len += languages[i].len;
|
|
||||||
}
|
}
|
||||||
if (copies == count) {
|
|
||||||
/* only one language is offered, nothing to do */
|
|
||||||
free (languages);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*language_count = count/copies;
|
*language_count = count/copies;
|
||||||
assert(count == *language_count * copies);
|
assert(count == *language_count * copies);
|
||||||
assert(len == (int) strlen(data));
|
|
||||||
/* verify expected structure of language choice information */
|
/* verify expected structure of language choice information */
|
||||||
for (int i = 1; i <= count; i++) {
|
for (int i = 1; i <= count; i++) {
|
||||||
if (i % *language_count) {
|
int j = i - *language_count;
|
||||||
assert(languages[i].type != 'o');
|
|
||||||
} else {
|
|
||||||
assert(languages[i].type == 'o');
|
|
||||||
}
|
|
||||||
int j = i - *language_count;
|
|
||||||
if (j > 0) {
|
if (j > 0) {
|
||||||
assert (!strcmp(languages[i].code, languages[j].code));
|
assert (!strcmp(languages[i].code, languages[j].code));
|
||||||
}
|
}
|
||||||
@@ -322,38 +325,49 @@ language_t* master_playlist_process_language(char * data, int *slices, int *lang
|
|||||||
char * select_master_playlist_language(airplay_video_t *airplay_video, char *master_playlist) {
|
char * select_master_playlist_language(airplay_video_t *airplay_video, char *master_playlist) {
|
||||||
int language_count, slices;
|
int language_count, slices;
|
||||||
language_t *languages;
|
language_t *languages;
|
||||||
|
assert(master_playlist);
|
||||||
if (!(languages = master_playlist_process_language(master_playlist,
|
if (!(languages = master_playlist_process_language(master_playlist,
|
||||||
&slices, &language_count))) {
|
&slices, &language_count))) {
|
||||||
return master_playlist;
|
return master_playlist;
|
||||||
}
|
}
|
||||||
/* audio is offered in multiple languages */
|
|
||||||
char *str = calloc(6 * language_count, sizeof(char));
|
|
||||||
int i;
|
|
||||||
char *ptr = str;
|
|
||||||
for (i = 0; i < language_count; i++) {
|
|
||||||
sprintf(ptr,"%s ", languages[i + 1].code);
|
|
||||||
ptr += strlen(languages[i + 1].code);
|
|
||||||
ptr++;
|
|
||||||
if ( i % 16 == 15) {
|
|
||||||
sprintf(ptr++,"\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i % 16 != 15) {
|
|
||||||
sprintf(ptr++,"\n");
|
|
||||||
}
|
|
||||||
printf("%d available languages: %s", language_count, str);
|
|
||||||
free(str);
|
|
||||||
|
|
||||||
const char *ptrc = airplay_video->lang;
|
/* audio is offered in multiple languages */
|
||||||
char *lang = NULL;
|
|
||||||
while (ptrc) {
|
char *code = NULL;
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
assert(airplay_video);
|
||||||
|
printf("%d available languages:\n\n", language_count);
|
||||||
|
int i_default = -1;
|
||||||
|
|
||||||
|
const char *language_name = get_language_name(airplay_video);
|
||||||
|
for (int i = 1; i <= language_count; i ++) {
|
||||||
|
if (language_name) {
|
||||||
|
if (!strcmp(language_name, languages[i].name)) {
|
||||||
|
i_default = i;
|
||||||
|
}
|
||||||
|
} else if (languages[i].is_default) {
|
||||||
|
i_default = i;
|
||||||
|
}
|
||||||
|
printf("%2d %-5.5s \"%s\" %s\n",i, languages[i].code, languages[i].name, (languages[i].is_default ? "(DEFAULT)" : ""));
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
assert(i_default >= 0);
|
||||||
|
|
||||||
|
const char *ptrc = airplay_video->lang;;
|
||||||
|
code = NULL;
|
||||||
|
name = NULL;
|
||||||
|
while (ptrc){
|
||||||
for (int i = 1; i <= language_count; i++) {
|
for (int i = 1; i <= language_count; i++) {
|
||||||
if (!strncmp(languages[i].code, ptrc, 2)) {
|
if (!strncmp(languages[i].code, ptrc, 2)) {
|
||||||
lang = languages[i].code;
|
code = languages[i].code;
|
||||||
|
name = languages[i].name;
|
||||||
|
printf("language choice: %s \"%s\" (based on prefered languages list %s)\n\n",
|
||||||
|
code, name, airplay_video->lang);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lang) {
|
if (code) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ptrc = strchr(ptrc,':');
|
ptrc = strchr(ptrc,':');
|
||||||
@@ -364,32 +378,54 @@ char * select_master_playlist_language(airplay_video_t *airplay_video, char *mas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lang) {
|
|
||||||
printf("language choice: %s (based on prefered languages list %s)\n\n",
|
if (!code) {
|
||||||
lang, airplay_video->lang);
|
code = languages[i_default].code;
|
||||||
} else {
|
name = languages[i_default].name;
|
||||||
if (airplay_video->lang) {
|
if (airplay_video->lang) {
|
||||||
printf("no match with prefered language list %s\n", airplay_video->lang);
|
printf("no match with prefered language list %s\n", airplay_video->lang);
|
||||||
}
|
}
|
||||||
lang = languages[language_count].code;
|
if (language_name) {
|
||||||
printf("default language choice: %s\n\n", lang);
|
printf("using HLS-specified language choice: %s \"%s\"\n\n", code, name);
|
||||||
|
} else {
|
||||||
|
printf("using default language choice: %s \"%s\"\n\n", code, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update stored language code, name if changed */
|
||||||
|
if (name != language_name) { /* compare addresses */
|
||||||
|
int len = strlen(name);
|
||||||
|
char *new_language_name = (char *) calloc(len + 1, sizeof(char));
|
||||||
|
memcpy(new_language_name, name, len);
|
||||||
|
set_language_name(airplay_video, new_language_name);
|
||||||
|
len = strlen(code);
|
||||||
|
char *new_language_code = (char *) calloc(len + 1, sizeof(char));
|
||||||
|
memcpy(new_language_code, code, len);
|
||||||
|
set_language_code(airplay_video, new_language_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
for (int i = 0; i < slices; i++) {
|
for (int i = 0; i < slices; i++) {
|
||||||
if (strlen(languages[i].code) == 0 || !strcmp(languages[i].code, lang)) {
|
if (strlen(languages[i].code) == 0 || !strcmp(languages[i].code, code)) {
|
||||||
len += languages[i].len;
|
len += languages[i].len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char *new_master_playlist = (char *) calloc(len + 1, sizeof(char));
|
char *new_master_playlist = (char *) calloc(len + 1, sizeof(char));
|
||||||
ptr = new_master_playlist;
|
|
||||||
|
char *ptr = new_master_playlist;
|
||||||
for (int i = 0; i < slices; i++) {
|
for (int i = 0; i < slices; i++) {
|
||||||
if (strlen(languages[i].code) == 0 || !strcmp(languages[i].code, lang)) {
|
if (strlen(languages[i].code) == 0 || !strcmp(languages[i].code, code)) {
|
||||||
strncpy(ptr, languages[i].start, languages[i].len);
|
strncpy(ptr, languages[i].start, languages[i].len);
|
||||||
ptr += languages[i].len;
|
ptr += languages[i].len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i <= slices - 2 ; i++) {
|
||||||
|
free (languages[i].name);
|
||||||
|
}
|
||||||
free (languages);
|
free (languages);
|
||||||
free(master_playlist);
|
free (master_playlist);
|
||||||
|
|
||||||
return new_master_playlist;
|
return new_master_playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user