diff options
author | Brendan Long <self@brendanlong.com> | 2013-10-04 15:47:55 -0700 |
---|---|---|
committer | Brendan Long <self@brendanlong.com> | 2013-10-04 15:47:55 -0700 |
commit | 7175f175cf1e9e2c3705e026fd02124a0ec85f86 (patch) | |
tree | 57fdb047bdad75b5972f5c685030433ace737676 | |
parent | dba0ed5cfd864cbfb197fc81000e1848ecf13241 (diff) | |
parent | 38998a5edb8082fa7f42c5dc8675a3354e6ebd3d (diff) |
Merge pull request #26 from cablelabs/parse-utilities
Created utility parse methods to parse both byte and npt ranges. Starte...
-rw-r--r-- | src/gstdlnasrc.c | 416 | ||||
-rw-r--r-- | src/gstdlnasrc.h | 4 |
2 files changed, 258 insertions, 162 deletions
diff --git a/src/gstdlnasrc.c b/src/gstdlnasrc.c index c035fab..abe11ef 100644 --- a/src/gstdlnasrc.c +++ b/src/gstdlnasrc.c @@ -81,7 +81,8 @@ static const gchar *HEAD_RESPONSE_HEADERS[] = { "CACHE-CONTROL", // 11 "CONTENT-LENGTH", // 12 "ACCEPT-RANGES", // 13 - "CONTENT-RANGE" // 14 + "CONTENT-RANGE", // 14 + "AVAILABLESEEKRANGE.DLNA.ORG" // 15 }; // Constants which represent indices in HEAD_RESPONSE_HEADERS string array @@ -101,21 +102,24 @@ static const gchar *HEAD_RESPONSE_HEADERS[] = { #define HEADER_INDEX_CONTENT_LENGTH 12 #define HEADER_INDEX_ACCEPT_RANGES 13 #define HEADER_INDEX_CONTENT_RANGE 14 +#define HEADER_INDEX_AVAILABLE_RANGE 15 // Count of field headers in HEAD_RESPONSE_HEADERS along with HEADER_INDEX_* constants -static const gint HEAD_RESPONSE_HEADERS_CNT = 15; +static const gint HEAD_RESPONSE_HEADERS_CNT = 16; -// Subfield headers within TIMESEEKRANGE.DLNA.ORG -static const gchar *TIME_SEEK_HEADERS[] = { +// Subfield headers which specify ranges +static const gchar *RANGE_HEADERS[] = { "NPT", // 0 "BYTES", // 1 + "CLEARTEXTBYTES", // 2 }; -// Subfield headers within ACCEPT-RANGES -static const gchar *ACCEPT_RANGES_NONE = "NONE"; - #define HEADER_INDEX_NPT 0 #define HEADER_INDEX_BYTES 1 +#define HEADER_INDEX_CLEAR_TEXT 2 + +// Subfield headers within ACCEPT-RANGES +static const gchar *ACCEPT_RANGES_NONE = "NONE"; // Subfield headers within CONTENTFEATURES.DLNA.ORG static const gchar *CONTENT_FEATURES_HEADERS[] = { @@ -246,9 +250,9 @@ static gboolean dlna_src_head_response_assign_field_value (GstDlnaSrc * static gboolean dlna_src_head_response_parse_time_seek (GstDlnaSrc * dlna_src, GstDlnaSrcHeadResponse * head_response, gint idx, gchar * field_str); -static gboolean dlna_src_head_response_parse_byte_range (GstDlnaSrc * dlna_src, - gint idx, gchar * field_str, guint64 * start_byte, guint64 * end_byte, - guint64 * total_bytes); +static gboolean +dlna_src_head_response_parse_available_range (GstDlnaSrc * dlna_src, + GstDlnaSrcHeadResponse * head_response, gint idx, gchar * field_str); static gboolean dlna_src_head_response_parse_content_features (GstDlnaSrc * dlna_src, GstDlnaSrcHeadResponse * head_response, gint idx, @@ -268,10 +272,6 @@ static gboolean dlna_src_head_response_parse_playspeeds (GstDlnaSrc * static gboolean dlna_src_head_response_parse_flags (GstDlnaSrc * dlna_src, GstDlnaSrcHeadResponse * head_response, gint idx, gchar * field_str); -static gboolean dlna_src_head_response_parse_dtcp_range (GstDlnaSrc * - dlna_src, GstDlnaSrcHeadResponse * head_response, gint idx, - gchar * field_str); - static gboolean dlna_src_head_response_parse_content_type (GstDlnaSrc * dlna_src, GstDlnaSrcHeadResponse * head_response, gint idx, gchar * field_str); @@ -301,6 +301,15 @@ static gboolean dlna_src_handle_query_segment (GstDlnaSrc * dlna_src, static gboolean dlna_src_handle_query_convert (GstDlnaSrc * dlna_src, GstQuery * query); +static gboolean dlna_src_parse_byte_range (GstDlnaSrc * dlna_src, + gchar * field_str, gint header_idx, guint64 * start_byte, + guint64 * end_byte, guint64 * total_bytes); + +static gboolean +dlna_src_parse_npt_range (GstDlnaSrc * dlna_src, gchar * npt_str, + gchar ** start_str, gchar ** stop_str, gchar ** total_str, + guint64 * start, guint64 * stop, guint64 * total); + static gboolean dlna_src_is_change_valid (GstDlnaSrc * dlna_src, gfloat rate, GstFormat format, guint64 start, GstSeekType start_type, guint64 stop, GstSeekType stop_type); @@ -325,6 +334,8 @@ static gboolean dlna_src_use_byte_range (GstDlnaSrc * dlna_src); static gboolean dlna_src_use_time_range (GstDlnaSrc * dlna_src); +static gboolean dlna_src_is_dtcp_encrypted (GstDlnaSrc * dlna_src); + #define gst_dlna_src_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstDlnaSrc, gst_dlna_src, GST_TYPE_BIN, @@ -849,12 +860,12 @@ dlna_src_use_byte_range (GstDlnaSrc * dlna_src) && dlna_src->server_info->time_seek_response_received) { // Check for non-encrypted content and range seek supported - if (!dlna_src->server_info->content_features->flag_link_protected_set && + if (!dlna_src_is_dtcp_encrypted (dlna_src) && dlna_src->server_info->content_features->op_range_supported) return TRUE; // Check for encrypted content and range seek supported - else if (dlna_src->server_info->content_features->flag_link_protected_set && + else if (dlna_src_is_dtcp_encrypted (dlna_src) && (dlna_src->server_info->content_features->flag_full_clear_text_set || dlna_src->server_info->content_features-> flag_limited_clear_text_set)) @@ -884,6 +895,21 @@ dlna_src_use_time_range (GstDlnaSrc * dlna_src) } /** + * Utility method which determines if content is dtcp/ip encrypted. + * + * @param dlna_src this element + * + * @return true if content is dtcp encrypted, false otherwise + */ +static gboolean +dlna_src_is_dtcp_encrypted (GstDlnaSrc * dlna_src) +{ + return dlna_src->server_info != NULL + && dlna_src->server_info->content_features != NULL + && dlna_src->server_info->content_features->flag_link_protected_set; +} + +/** * Responds to a segment query by returning rate along with start and stop * * @param dlna_src this element @@ -1365,10 +1391,10 @@ dlna_src_adjust_http_src_headers (GstDlnaSrc * dlna_src, gfloat rate, "Not adjusting with playspeed or time seek range "); // If dtcp protected content and rate = 1.0, add range.dtcp.com header - if ((rate == 1.0) && (format == GST_FORMAT_BYTES) - && (dlna_src->server_info->content_features->flag_link_protected_set)) { - g_snprintf (range_dtcp_field_value, 64, - "%s%" G_GUINT64_FORMAT "-", range_dtcp_field_value_prefix, start); + if (rate == 1.0 && format == GST_FORMAT_BYTES + && dlna_src_is_dtcp_encrypted (dlna_src)) { + g_snprintf (range_dtcp_field_value, 64, "%s%" G_GUINT64_FORMAT "-", + range_dtcp_field_value_prefix, start); // Add header to structure gst_structure_set (extra_headers_struct, range_dtcp_field_name, @@ -1497,9 +1523,7 @@ dlna_src_set_uri (GstDlnaSrc * dlna_src, const gchar * value) // Setup elements based on HEAD response // Use flag to determine if content is DTCP/IP protected - if ((dlna_src->server_info != NULL) && - (dlna_src->server_info->content_features != NULL) && - (dlna_src->server_info->content_features->flag_link_protected_set)) { + if (dlna_src_is_dtcp_encrypted (dlna_src)) { // Setup the dtcpip decrypter element, this will also ghost pad the // src pad of the bin if (!dlna_src_dtcp_setup (dlna_src)) { @@ -2276,6 +2300,12 @@ dlna_src_head_response_init_struct (GstDlnaSrc * dlna_src, head_response->byte_seek_end = 0; head_response->byte_seek_total = 0; + // {"CLEARTEXTBYTES", BYTE_RANGE_TYPE}, + head_response->clear_text_idx = HEADER_INDEX_CLEAR_TEXT; + + // {"AVAILABLESEEKRANGE.DLNA.ORG", STRING_TYPE}, + head_response->available_range_idx = HEADER_INDEX_AVAILABLE_RANGE; + // {CONTENT RANGE DTCP, BYTE_RANGE_TYPE}, head_response->dtcp_range_idx = HEADER_INDEX_DTCP_RANGE; head_response->dtcp_range_start = 0; @@ -2434,13 +2464,12 @@ dlna_src_head_response_assign_field_value (GstDlnaSrc * dlna_src, case HEADER_INDEX_CONTENT_LENGTH: if ((ret_code = sscanf (field_str, "%31[^:]:%" G_GUINT64_FORMAT, tmp1, - &guint64_value)) != 2) { + &guint64_value)) != 2) GST_WARNING_OBJECT (dlna_src, "Problems parsing Content Length from HEAD response field header %s, value: %s, retcode: %d", HEAD_RESPONSE_HEADERS[idx], field_str, ret_code); - } else { + else head_response->content_length = guint64_value; - } break; case HEADER_INDEX_ACCEPT_RANGES: @@ -2450,12 +2479,11 @@ dlna_src_head_response_assign_field_value (GstDlnaSrc * dlna_src, break; case HEADER_INDEX_CONTENT_RANGE: - if (!dlna_src_head_response_parse_byte_range (dlna_src, idx, field_str, - NULL, NULL, &head_response->content_length)) { + if (!dlna_src_parse_byte_range (dlna_src, field_str, HEADER_INDEX_BYTES, + NULL, NULL, &head_response->content_length)) GST_WARNING_OBJECT (dlna_src, "Problems parsing Content Range from HEAD response field header %s, value: %s, retcode: %d", HEAD_RESPONSE_HEADERS[idx], field_str, ret_code); - } break; case HEADER_INDEX_SERVER: @@ -2483,29 +2511,35 @@ dlna_src_head_response_assign_field_value (GstDlnaSrc * dlna_src, case HEADER_INDEX_TIMESEEKRANGE: if (!dlna_src_head_response_parse_time_seek (dlna_src, head_response, idx, - field_str)) { + field_str)) GST_WARNING_OBJECT (dlna_src, "Problems with HEAD response field header %s, value: %s", HEAD_RESPONSE_HEADERS[idx], field_str); - } break; case HEADER_INDEX_CONTENTFEATURES: if (!dlna_src_head_response_parse_content_features - (dlna_src, head_response, idx, field_str)) { + (dlna_src, head_response, idx, field_str)) GST_WARNING_OBJECT (dlna_src, "Problems with HEAD response field header %s, value: %s", HEAD_RESPONSE_HEADERS[idx], field_str); - } break; case HEADER_INDEX_DTCP_RANGE: - if (!dlna_src_head_response_parse_dtcp_range (dlna_src, head_response, - idx, field_str)) { + if (!dlna_src_parse_byte_range (dlna_src, field_str, HEADER_INDEX_BYTES, + &head_response->dtcp_range_start, + &head_response->dtcp_range_end, &head_response->dtcp_range_total)) + GST_WARNING_OBJECT (dlna_src, + "Problems with HEAD response field header %s, value: %s", + HEAD_RESPONSE_HEADERS[idx], field_str); + break; + + case HEADER_INDEX_AVAILABLE_RANGE: + if (!dlna_src_head_response_parse_available_range (dlna_src, + head_response, idx, field_str)) GST_WARNING_OBJECT (dlna_src, "Problems with HEAD response field header %s, value: %s", HEAD_RESPONSE_HEADERS[idx], field_str); - } break; case HEADER_INDEX_VARY: @@ -2545,77 +2579,96 @@ static gboolean dlna_src_head_response_parse_time_seek (GstDlnaSrc * dlna_src, GstDlnaSrcHeadResponse * head_response, gint idx, gchar * field_str) { - gchar tmp1[32] = { 0 }; - gchar tmp2[32] = { 0 }; - gchar tmp3[32] = { 0 }; - gchar tmp4[132] = { 0 }; - gchar *tmp_str1 = NULL; - gchar *tmp_str2 = NULL; - gint ret_code = 0; - - // *TODO* - need more sophisticated parsing of NPT to handle different formats - // Extract start and end NPT - tmp_str2 = strstr (field_str, TIME_SEEK_HEADERS[HEADER_INDEX_NPT]); - tmp_str1 = strstr (tmp_str2, "="); - if (tmp_str1 != NULL) { - tmp_str1++; - // *TODO* - add logic to deal with '*' - if ((ret_code = - sscanf (tmp_str1, "%31[^-]-%31[^/]/%31s %131s", tmp1, tmp2, tmp3, - tmp4)) != 4) { - GST_WARNING_OBJECT (dlna_src, - "Problems parsing NPT from HEAD response field header %s, value: %s, retcode: %d, tmp: %s, %s, %s", - HEAD_RESPONSE_HEADERS[idx], tmp_str1, ret_code, tmp1, tmp2, tmp3); - } else { - head_response->time_seek_npt_start_str = g_strdup (tmp1); - head_response->time_seek_npt_end_str = g_strdup (tmp2); - head_response->time_seek_npt_duration_str = g_strdup (tmp3); - - dlna_src_npt_to_nanos (dlna_src, - head_response->time_seek_npt_start_str, - &head_response->time_seek_npt_start); - dlna_src_npt_to_nanos (dlna_src, - head_response->time_seek_npt_end_str, - &head_response->time_seek_npt_end); - dlna_src_npt_to_nanos (dlna_src, - head_response->time_seek_npt_duration_str, - &head_response->time_seek_npt_duration); - - head_response->time_seek_response_received = TRUE; - } - } else { - GST_WARNING_OBJECT (dlna_src, - "No NPT found in time seek range HEAD response field header %s, idx: %d, value: %s", - HEAD_RESPONSE_HEADERS[idx], idx, field_str); - } + // Extract start and end NPT from TimeSeekRange header + if (!dlna_src_parse_npt_range (dlna_src, field_str, + &head_response->time_seek_npt_start_str, + &head_response->time_seek_npt_end_str, + &head_response->time_seek_npt_duration_str, + &head_response->time_seek_npt_start, + &head_response->time_seek_npt_end, + &head_response->time_seek_npt_duration)) + // Return, errors which have been logged already + return FALSE; + else + head_response->time_seek_response_received = TRUE; - if (!dlna_src_head_response_parse_byte_range (dlna_src, idx, field_str, + // Extract start and end bytes from TimeSeekRange header + if (!dlna_src_parse_byte_range (dlna_src, field_str, HEADER_INDEX_BYTES, &head_response->byte_seek_start, - &head_response->byte_seek_end, &head_response->byte_seek_total)) { - GST_WARNING_OBJECT (dlna_src, - "Problems getting byte range from HEAD response field header %s, idx: %d, value: %s", - HEAD_RESPONSE_HEADERS[idx], idx, field_str); + &head_response->byte_seek_end, &head_response->byte_seek_total)) + // Return, errors which have been logged already + return FALSE; + + return TRUE; +} + +/** + * AvailableSeekRange header formatting as specified in DLNA 7.5.4.3.2.20.7: + * + * availableSeekRange.dlna.org: 0 npt=0:00:00.000-0:00:48.716 bytes=0-5219255 cleartextbytes=0-5219255 + * + * The time seek range portion can have two different formats + * Either: + * "npt = 1*DIGIT["."1*3DIGIT] + * ntp sec = 0.232, or 1 or 15 or 16.652 (leading at one or more digits, + * optionally followed by decimal point and 3 digits) + * OR + * "npt=00:00:00.000" where format is HH:MM:SS.mmm (hours, minutes, seconds, milliseconds) + * + * @param dlna_src this element instance + * @param idx index which describes HEAD response field and type + * @param fieldStr string containing HEAD response field header and value + * + * @return returns TRUE + */ +static gboolean +dlna_src_head_response_parse_available_range (GstDlnaSrc * dlna_src, + GstDlnaSrcHeadResponse * head_response, gint idx, gchar * field_str) +{ + // Extract start and end NPT from availableSeekRange header + if (!dlna_src_parse_npt_range (dlna_src, field_str, + &head_response->time_seek_npt_start_str, + &head_response->time_seek_npt_end_str, + &head_response->time_seek_npt_duration_str, + &head_response->time_seek_npt_start, + &head_response->time_seek_npt_end, + &head_response->time_seek_npt_duration)) + // Return, errors which have been logged already + return FALSE; + + if (!dlna_src_is_dtcp_encrypted (dlna_src)) { + // Extract start and end bytes from availableSeekRange header using bytes + if (!dlna_src_parse_byte_range (dlna_src, field_str, + HEADER_INDEX_BYTES, &head_response->byte_seek_start, + &head_response->byte_seek_end, &head_response->byte_seek_total)) + // Return, errors which have been logged already + return FALSE; } else { - GST_DEBUG_OBJECT (dlna_src, "byte seek total: %" G_GUINT64_FORMAT, - head_response->byte_seek_total); + // Extract start and end bytes from availableSeekRange header using clear text bytes + if (!dlna_src_parse_byte_range (dlna_src, field_str, + HEADER_INDEX_CLEAR_TEXT, &head_response->byte_seek_start, + &head_response->byte_seek_end, &head_response->byte_seek_total)) + // Return, errors which have been logged already + return FALSE; } + return TRUE; } /** * Parse the byte range which may be contained in the following headers: * - * TimeSeekRange header formatting as specified in DLNA 7.4.40.5: - * * TimeSeekRange.dlna.org : npt=335.1-336.1/40445.4 bytes=1539686400-1540210688/304857907200 * * Content-Range: bytes 0-1859295/1859295 * * Content-Range.dtcp.com: bytes=0-9931928/9931929 * + * availableSeekRange.dlna.org: 0 npt=0:00:00.000-0:00:48.716 bytes=0-5219255 cleartextbytes=0-5219255 + * * @param dlna_src this element instance - * @param idx index which describes HEAD response field and type * @param field_str string containing HEAD response field header and value + * @param header_idx index which identifies which byte header to use - bytes or cleartextbytes * @param start_byte starting byte position read from header response field * @param end_byte end byte position read from header response field * @param total_bytes total bytes read from header response field @@ -2623,106 +2676,145 @@ dlna_src_head_response_parse_time_seek (GstDlnaSrc * dlna_src, * @return returns TRUE */ static gboolean -dlna_src_head_response_parse_byte_range (GstDlnaSrc * dlna_src, gint idx, - gchar * field_str, guint64 * start_byte, guint64 * end_byte, - guint64 * total_bytes) +dlna_src_parse_byte_range (GstDlnaSrc * dlna_src, + gchar * field_str, gint header_index, guint64 * start_byte, + guint64 * end_byte, guint64 * total_bytes) { - gchar *tmp_str1 = NULL; - gchar *tmp_str2 = NULL; + gchar *header = NULL; + gchar *header_value = NULL; + gint ret_code = 0; guint64 ullong1 = 0; guint64 ullong2 = 0; guint64 ullong3 = 0; - // Extract start and end BYTES - tmp_str2 = strstr (field_str, TIME_SEEK_HEADERS[HEADER_INDEX_BYTES]); - if (tmp_str2 != NULL) { - tmp_str1 = strstr (tmp_str2, "="); - if (tmp_str1 == NULL) { - // Try for a space separator - tmp_str1 = strstr (tmp_str2, " "); - } - if (tmp_str1 != NULL) { - tmp_str1++; - // *TODO* - add logic to deal with '*' - if ((ret_code = - sscanf (tmp_str1, - "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "/%" - G_GUINT64_FORMAT, &ullong1, &ullong2, &ullong3)) != 3) { - GST_WARNING_OBJECT (dlna_src, - "Problems parsing BYTES from HEAD response field headr %s, idx: %d, value: %s, retcode: %d, ullong: %" - G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT - ", %" G_GUINT64_FORMAT, - HEAD_RESPONSE_HEADERS[idx], idx, tmp_str1, - ret_code, ullong1, ullong2, ullong3); - } else { - if (start_byte) - *start_byte = ullong1; - if (end_byte) - *end_byte = ullong2; - if (total_bytes) - *total_bytes = ullong3; - } - } else { + // Extract BYTES portion of header value + header = strstr (field_str, RANGE_HEADERS[header_index]); + if (header) + header_value = strstr (header, "="); + if (!header_value) + header_value = strstr (header, " "); + if (header_value) + header_value++; + else { + GST_WARNING_OBJECT (dlna_src, + "Bytes not included in header from HEAD response field header value: %s", + field_str); + return FALSE; + } + + // Determine if byte string includes total which is not an * + if (strstr (header_value, "/") && !strstr (header_value, "*")) { + // Extract start and end and total BYTES + if ((ret_code = + sscanf (header_value, + "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "/%" + G_GUINT64_FORMAT, &ullong1, &ullong2, &ullong3)) != 3) { GST_WARNING_OBJECT (dlna_src, - "No BYTES found in field header %s, idx: %d, value: %s", - HEAD_RESPONSE_HEADERS[idx], idx, field_str); + "Problems parsing BYTES from HEAD response field header %s, value: %s, retcode: %d, ullong: %" + G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT + ", %" G_GUINT64_FORMAT, + field_str, header_value, ret_code, ullong1, ullong2, ullong3); + return FALSE; } } else { - GST_WARNING_OBJECT (dlna_src, - "No BYTES= found in HEAD response field header %s, idx: %d, value: %s", - HEAD_RESPONSE_HEADERS[idx], idx, field_str); + if ((ret_code = + sscanf (header_value, + "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, &ullong1, + &ullong2)) != 2) { + GST_WARNING_OBJECT (dlna_src, + "Problems parsing BYTES from HEAD response field header %s, value: %s, retcode: %d, ullong: %" + G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT, field_str, header_value, + ret_code, ullong1, ullong2); + return FALSE; + } } + + if (start_byte) + *start_byte = ullong1; + if (end_byte) + *end_byte = ullong2; + if (total_bytes) + *total_bytes = ullong3; + return TRUE; } /** - * DTCP Range header formatting: + * Parse the npt (normal play time) range which may be contained in the following headers: * - * Content-Range.dtcp.com : bytes=1539686400-1540210688/304857907200 + * TimeSeekRange.dlna.org : npt=335.1-336.1/40445.4 bytes=1539686400-1540210688/304857907200 * - * @param dlna_src this element instance - * @param idx index which describes HEAD response field and type - * @param fieldStr string containing HEAD response field header and value + * availableSeekRange.dlna.org: 0 npt=0:00:00.000-0:00:48.716 bytes=0-5219255 cleartextbytes=0-5219255 * - * @return returns TRUE + * @param dlna_src this element instance + * @param field_str string containing HEAD response field header and value + * @param start_str starting time in string form read from header response field + * @param stop_str end time in string form read from header response field + * @param total_str total time in string form read from header response field + * @param start starting time in nanoseconds converted from string representation + * @param stop end time in nanoseconds converted from string representation + * @param total total time in nanoseconds converted from string representation + * + * @return returns TRUE */ static gboolean -dlna_src_head_response_parse_dtcp_range (GstDlnaSrc * dlna_src, - GstDlnaSrcHeadResponse * head_response, gint idx, gchar * field_str) +dlna_src_parse_npt_range (GstDlnaSrc * dlna_src, gchar * field_str, + gchar ** start_str, gchar ** stop_str, gchar ** total_str, + guint64 * start, guint64 * stop, guint64 * total) { - gchar *tmp_str1 = NULL; - gchar *tmp_str2 = NULL; + gchar *header = NULL; + gchar *header_value = NULL; + gint ret_code = 0; - guint64 ullong1 = 0; - guint64 ullong2 = 0; - guint64 ullong3 = 0; + gchar tmp1[32] = { 0 }; + gchar tmp2[32] = { 0 }; + gchar tmp3[32] = { 0 }; - // Extract start and end BYTES same format as TIME SEEK BYTES header - tmp_str2 = strstr (field_str, TIME_SEEK_HEADERS[HEADER_INDEX_BYTES]); - if (tmp_str2 != NULL) { - tmp_str1 = - tmp_str2 + strlen (TIME_SEEK_HEADERS[HEADER_INDEX_BYTES] + 1) + 1; - // *TODO* - add logic to deal with '*' + // Extract NPT portion of header value + header = strstr (field_str, RANGE_HEADERS[HEADER_INDEX_NPT]); + if (header) + header_value = strstr (header, "="); + if (header_value) + header_value++; + else { + GST_WARNING_OBJECT (dlna_src, + "Problems parsing npt from HEAD response field header value: %s", + field_str); + return FALSE; + } + + // Determine if npt string includes total + if (strstr (header_value, "/")) { if ((ret_code = - sscanf (tmp_str1, - "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "/%" - G_GUINT64_FORMAT, &ullong1, &ullong2, &ullong3)) != 3) { + sscanf (header_value, "%31[^-]-%31[^/]/%31s %*s", tmp1, tmp2, + tmp3)) != 3) { GST_WARNING_OBJECT (dlna_src, - "Problems parsing BYTES from HEAD response field header %s, idx: %d, value: %s, retcode: %d, ullong: %" - G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", %" - G_GUINT64_FORMAT, HEAD_RESPONSE_HEADERS[idx], idx, - tmp_str1, ret_code, ullong1, ullong2, ullong3); - } else { - head_response->dtcp_range_start = ullong1; - head_response->dtcp_range_end = ullong2; - head_response->dtcp_range_total = ullong3; + "Problems parsing NPT from HEAD response field header %s, value: %s, retcode: %d, tmp: %s, %s, %s", + field_str, header_value, ret_code, tmp1, tmp2, tmp3); + return FALSE; } + + *total_str = g_strdup (tmp3); + if (strcmp (*total_str, "*") != 0) + if (!dlna_src_npt_to_nanos (dlna_src, *total_str, total)) + return FALSE; } else { - GST_WARNING_OBJECT (dlna_src, - "No BYTES= found in dtcp range HEAD response field header %s, idx: %d, value: %s", - HEAD_RESPONSE_HEADERS[idx], idx, field_str); + if ((ret_code = sscanf (header_value, "%31[^-]-%31s %*s", tmp1, tmp2)) != 2) { + GST_WARNING_OBJECT (dlna_src, + "Problems parsing NPT from HEAD response field header %s, value: %s, retcode: %d, tmp: %s, %s", + field_str, header_value, ret_code, tmp1, tmp2); + return FALSE; + } } + *start_str = g_strdup (tmp1); + if (!dlna_src_npt_to_nanos (dlna_src, *start_str, start)) + return FALSE; + + *stop_str = g_strdup (tmp2); + if (!dlna_src_npt_to_nanos (dlna_src, *stop_str, stop)) + return FALSE; + return TRUE; } diff --git a/src/gstdlnasrc.h b/src/gstdlnasrc.h index 92e3cd8..49f2e6a 100644 --- a/src/gstdlnasrc.h +++ b/src/gstdlnasrc.h @@ -140,11 +140,15 @@ struct _GstDlnaSrcHeadResponse guint64 byte_seek_total; gint byte_seek_idx; + gint clear_text_idx; + guint64 dtcp_range_start; guint64 dtcp_range_end; guint64 dtcp_range_total; gint dtcp_range_idx; + gint available_range_idx; + gchar* transfer_mode; gint transfer_mode_idx; |