rendered paste bodyIndex: libhb/muxmp4.c===================================================================--- libhb/muxmp4.c (revision 1364)+++ libhb/muxmp4.c (working copy)@@ -9,6 +9,8 @@ #include "hb.h" +#include "srt.h"+ void AddIPodUUID(MP4FileHandle, MP4TrackId); struct hb_mux_object_s@@ -27,6 +29,9 @@ MP4TrackId chapter_track; int current_chapter; uint64_t chapter_duration;+ + /* Subtitle stuff for muxing */+ MP4TrackId subtitle_track; }; struct hb_mux_data_s@@ -119,7 +124,114 @@ } +void MP4SetTrackYTranslation(const MP4FileHandle file,+ const MP4TrackId track,+ const u_int16_t translation)+{+ uint8_t* val;+ uint8_t nval[38];+ uint32_t *ptr32 = (uint32_t*) (nval + 2);+ uint32_t size;+ MP4GetTrackBytesProperty(file, track, "tkhd.reserved3", &val, &size);+ + memcpy(nval, val, size);+ + const uint32_t ytranslation = translation * 0x10000;+ +#ifdef WORDS_BIGENDIAN+ ptr32[7] = ytranslation;+#else+ /* we need to switch the endianness, as the file format expects big endian */+ ptr32[7] = ((ytranslation & 0x000000FF) << 24) + ((ytranslation & 0x0000FF00) << 8) + ((ytranslation & 0x00FF0000) >> 8) + ((ytranslation & 0xFF000000) >> 24);+#endif+ + MP4SetTrackBytesProperty(file, track, "tkhd.reserved3", nval, size); +}+ /**********************************************************************+ * MP4CreateSubtitleTrack+ **********************************************************************+ * Creates a new subtitle track+ *********************************************************************/+MP4TrackId MP4CreateSubtitleTrack(const MP4FileHandle file,+ const MP4TrackId refTrack,+ const uint16_t height,+ const uint16_t width,+ const uint16_t translation,+ const uint16_t language_code)+{+ const MP4TrackId subtitleTrack = MP4AddSubtitleTrack(file, refTrack);+ + MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.mdhd.language", language_code);+ MP4SetTrackFloatProperty(file, subtitleTrack, "tkhd.width", width);+ MP4SetTrackFloatProperty(file, subtitleTrack, "tkhd.height", height);+ + MP4SetTrackIntegerProperty(file, subtitleTrack, "tkhd.alternate_group", 2);+ + MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.defTextBoxTop", 0);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.defTextBoxLeft", 0);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.defTextBoxBottom", 50);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.defTextBoxRight", 0);+ + MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.fontID", 1);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.fontSize", 12);+ + MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.horizontalJustification", 1);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.verticalJustification", 255);+ + MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.fontColorRed", 255);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.fontColorGreen", 255);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.fontColorBlue", 255);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.fontColorAlpha", 255);+ + MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.bgColorRed", 0);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.bgColorGreen", 0);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.bgColorBlue", 0);+ MP4SetTrackIntegerProperty(file, subtitleTrack, "mdia.minf.stbl.stsd.tx3g.bgColorAlpha", 255);+ + MP4SetTrackYTranslation(file, subtitleTrack, translation);+ + MP4SetTrackTimeScale(file, subtitleTrack, 1000); // Set to ms++ return subtitleTrack;+}++void MP4WriteSubtitleSample(const MP4FileHandle file,+ const MP4TrackId track,+ const char* string,+ const long duration,+ const long offset)+{+ if (duration <= 0)+ return;+ + if (offset) {+ // Write the offset...+ u_int8_t empty[2] = {0,0};+ MP4WriteSample(file,+ track,+ empty,+ 2,+ duration,+ 0, true);+ }++ // .. and write the actual sample+ const size_t stringLength = strlen(string);+ u_int8_t buffer[1024];+ memcpy(buffer+2, string, strlen(string)); // strlen > 1024 -> booom+ buffer[0] = (stringLength >> 8) & 0xff;+ buffer[1] = stringLength & 0xff;+ + MP4WriteSample(file,+ track,+ buffer,+ stringLength + 2,+ duration,+ 0, true); +}++/********************************************************************** * MP4Init ********************************************************************** * Allocates hb_mux_data_t structures, create file and write headers@@ -335,7 +447,26 @@ m->chapter_duration = 0; m->current_chapter = job->chapter_start; }-+ + const uint16_t subtitleHeight = 60;+ m->subtitle_track = MP4CreateSubtitleTrack(m->file,+ mux_data->track,+ subtitleHeight,+ m->job->width,+ m->job->height - subtitleHeight,+ language_code);+ + + char filename[] = "/Users/ben/Developer/SrtParser/test.srt";+ struct srt_entry_s* subtitles = srt_readfile(filename);+ while (subtitles) {+ MP4WriteSubtitleSample(m->file, m->subtitle_track, subtitles->text, subtitles->offset, subtitles->duration); + subtitles = subtitles->next;+ }+ + srt_free_entries(subtitles);+ + /* Add encoded-by metadata listing version and build date */ char *tool_string; tool_string = (char *)malloc(80);@@ -387,7 +518,8 @@ hb_error("Failed to write to output file, disk full?"); *job->die = 1; }- free(sample);+ + free(sample); m->current_chapter++; m->chapter_duration += duration; }@@ -465,9 +597,10 @@ hb_error("Failed to write to output file, disk full?"); *job->die = 1; }- free(sample);+ + free(sample); }-+ if (job->areBframes) { // Insert track edit to get A/V back in sync. The edit amount is@@ -507,4 +640,3 @@ m->job = job; return m; }-Index: libhb/srt.c===================================================================--- libhb/srt.c (revision 0)+++ libhb/srt.c (revision 0)@@ -0,0 +1,134 @@+#include "srt.h"+#include <stdlib.h>+#include <stdio.h>+#include <string.h>++struct start_and_end {+ unsigned long start, end;+};++static struct start_and_end read_time_from_string(const char* timeString) {+ // for ex. 00:00:15,248 --> 00:00:16,545+ + long houres1, minutes1, seconds1, milliseconds1,+ houres2, minutes2, seconds2, milliseconds2;+ + sscanf(timeString, "%d:%d:%d,%d --> %d:%d:%d,%d\n", &houres1, &minutes1, &seconds1, &milliseconds1,+ &houres2, &minutes2, &seconds2, &milliseconds2);+ + struct start_and_end result = {milliseconds1 + seconds1*1000 + minutes1*60000 + houres1*36000,+ milliseconds2 + seconds2*1000 + minutes2*60000 + houres2*36000};+ return result;+}++enum+{+ k_state_inEntry,+ k_state_potential_new_entry,+ k_state_timecode,+};++struct srt_entry_s* srt_readfile(const char* filename)+{+ FILE *file = fopen ( filename, "r" );+ + if (file == NULL)+ return NULL;+ + char line_buffer[1024];+ unsigned long current_time = 0,+ number_of_entries = 0,+ current_state = k_state_potential_new_entry;+ + struct srt_entry_s *first_entry = malloc(sizeof(struct srt_entry_s)),+ *current_entry = first_entry;+ memset(first_entry, 0, sizeof(struct srt_entry_s));+ + while (fgets(line_buffer,sizeof(line_buffer),file)) {+ switch (current_state)+ {+ case k_state_timecode:+ {+ struct start_and_end timing = read_time_from_string(line_buffer); + + current_entry->duration = timing.end - timing.start;+ current_entry->offset = timing.start - current_time;+ + current_time = timing.end;+ + current_state = k_state_inEntry;+ continue; + }+ + case k_state_inEntry:+ {+ // If the current line is empty, we assume this is the+ // seperation betwene two entries. In case we are wrong,+ // the mistake is corrected in the next state.+ if (strcmp(line_buffer, "\n") == 0 || strcmp(line_buffer, "\r\n") == 0) { + current_state = k_state_potential_new_entry;+ continue;+ }+ + // Append the current line to the entry's text buffer;+ strncat(current_entry->text, line_buffer, 1024);+ + break; + }+ + case k_state_potential_new_entry:+ {+ char endpoint[] = "\0";+ const unsigned long potential_entry_number = strtol(line_buffer, (char**)&endpoint, 10);+ + // Is this really new next entry begin?+ if (potential_entry_number == number_of_entries + 1) {+ // We actuall found the next entry - or a really rare error condition+ + // The first entry was preallocated - all others are alloced here+ // plus we overwrite zero-duration entries+ if (number_of_entries != 0) {+ current_entry->next = malloc(sizeof(struct srt_entry_s)); + current_entry = current_entry->next;+ }+ + memset(current_entry, 0, sizeof(struct srt_entry_s));+ + ++number_of_entries;+ current_state = k_state_timecode;+ continue;+ } else {+ // Well.. looks like we are in the wrong mode.. lets add the+ // newline we misinterpreted...+ strncat(current_entry->text, "\n", 1024);+ current_state = k_state_inEntry;+ }+ + break;+ }+ }+ }+ + fclose ( file );+ + // Since the number of entries is incremented when we find the next entry,+ // we missed the lastone+ if (strlen(current_entry->text)) {+ ++number_of_entries;+ }+ + // No entries found - free the preallocaed firstone+ if (number_of_entries == 0) {+ free(first_entry);+ return NULL;+ }+ + return first_entry;+}++void srt_free_entries(struct srt_entry_s* entries)+{+ if (entries && entries->next)+ srt_free_entries(entries->next);+ free(entries);+}\ No newline at end of fileIndex: libhb/srt.h===================================================================--- libhb/srt.h (revision 0)+++ libhb/srt.h (revision 0)@@ -0,0 +1,11 @@+#pragma once++struct srt_entry_s {+ long offset, duration;+ char text[1024];+ + struct srt_entry_s* next;+};++struct srt_entry_s* srt_readfile(const char* filename);+void srt_free_entries(struct srt_entry_s* entries);\ No newline at end of file