1/*
2* Copyright (c) 2014 Intel Corporation.  All rights reserved.
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17#ifndef LOG_DUMP_HELPER_INCLUDED
18#define LOG_DUMP_HELPER_INCLUDED
19
20#ifndef LOG_TAG
21#error "Before including this file, must #define LOG_TAG and #include <utils/Log.h>"
22#endif
23
24#if LOG_NDEBUG == 0
25
26// We have dump routines for the structures defined in the following files:
27#include "VideoFrameInfo.h"
28#include "ProtectedDataBuffer.h"
29
30// The following helps to use these dump routines from command line unit tests:
31#ifdef ANDROID
32#define DUMP_EOL    ""
33#else
34#define LOGV    printf
35#define LOGE    printf
36#define DUMP_EOL    "\n"
37#endif // ANDROID
38
39#ifndef log_helper_min
40#define log_helper_min(a,b) ((a) < (b) ? (a) : (b))
41#endif // log_helper_min
42
43static inline void Copy4Bytes(void* dst, const void* src)
44{
45    // Don't check input pointers for NULL: this is internal function,
46    // and if you pass NULL to it, your code deserves to crash.
47
48    uint8_t* bdst = (uint8_t*) dst ;
49    const uint8_t* bsrc = (const uint8_t*) src ;
50
51    *bdst++ = *bsrc++ ;
52    *bdst++ = *bsrc++ ;
53    *bdst++ = *bsrc++ ;
54    *bdst = *bsrc ;
55}
56// End of Copy4Bytes()
57
58static void DumpBufferToString(char* str, uint32_t strSize, const uint8_t* start, uint32_t size)
59{
60    if (str == NULL || strSize == 0 || start == NULL || size == 0)
61    {
62        LOGV("Error: invalid parameters to %s", __FUNCTION__) ;
63        return ;
64    }
65
66    char* s = str ;
67    char* send = str + strSize ;
68
69    const uint8_t* byte = start ;
70    const uint8_t* end = start + size ;
71
72    while (byte < end && s < send)
73    {
74        s += snprintf(s, strSize - (s - str), "%02x ", *byte) ;
75        ++byte ;
76    }
77}
78// End of DumpBufferToString()
79
80static void DumpNaluDataBuffer(uint32_t nalu, const uint8_t* start, uint32_t size)
81{
82    if (start == NULL || size == 0)
83    {
84        LOGV("NALU-dump: error: invalid parameters to %s", __FUNCTION__) ;
85        return ;
86    }
87
88    const uint32_t STR_SIZE = 1024 ;
89    char str[STR_SIZE] = {0} ;
90
91    DumpBufferToString(str, STR_SIZE, start, size) ;
92
93    LOGV("NALU-dump(nalu %u): data: %s" DUMP_EOL, nalu, str) ;
94}
95// End of DumpNaluDataBuffer()
96
97static void DumpBuffer(const char* prefix, const uint8_t* start, uint32_t size)
98{
99    if (start == NULL || size == 0)
100    {
101        LOGV("Error: invalid parameters to %s", __FUNCTION__) ;
102        return ;
103    }
104
105    if (prefix == NULL)
106    {
107        prefix = "" ;
108    }
109
110    const uint32_t STR_SIZE = 1024 ;
111    char str[STR_SIZE] = {0} ;
112
113    DumpBufferToString(str, STR_SIZE, start, size) ;
114
115    LOGV("%s: ptr=%p, size=%u, data=%s" DUMP_EOL, prefix, start, size, str) ;
116}
117// End of DumpBuffer()
118
119static void DumpNaluHeaderBuffer(const uint8_t* const start, uint32_t size)
120{
121    if (start == NULL || size == 0)
122    {
123        LOGV("Error: invalid parameters to %s", __FUNCTION__) ;
124        return ;
125    }
126
127    const uint8_t* current = start ;
128
129    uint32_t numNALUs = 0 ;
130    Copy4Bytes(&numNALUs, current) ;
131    current += sizeof(numNALUs) ;
132
133    LOGV("NALU-dump: num NALUs = %u\n", numNALUs) ;
134
135    if (numNALUs > MAX_NALUS_IN_FRAME)
136    {
137        LOGE("NALU-dump: ERROR, num NALUs is too big (%u)" DUMP_EOL, numNALUs) ;
138    }
139
140    for (uint32_t nalu = 0; nalu < numNALUs; ++nalu)
141    {
142        uint32_t imr_offset = 0 ;
143        Copy4Bytes(&imr_offset, current) ;
144        current += sizeof(imr_offset) ;
145
146        uint32_t nalu_size = 0 ;
147        Copy4Bytes(&nalu_size, current) ;
148        current += sizeof(nalu_size) ;
149
150        uint32_t data_size = 0 ;
151        Copy4Bytes(&data_size, current) ;
152        current += sizeof(data_size) ;
153
154        LOGV("NALU-dump(nalu %u): imr_offset = %u, nalu_size = %u, data_size = %u" DUMP_EOL,
155            nalu, imr_offset, nalu_size, data_size) ;
156
157        DumpNaluDataBuffer(nalu, current, data_size) ;
158
159        // Skip past the data
160        current += data_size ;
161    }
162    // End of for
163}
164// End of DumpNaluHeaderBuffer()
165
166static const char* DrmSchemeToString(uint32_t drmScheme)
167{
168    switch(drmScheme)
169    {
170        case DRM_SCHEME_NONE:
171            return "None" ;
172
173        case DRM_SCHEME_WV_CLASSIC:
174            return "WV Classic" ;
175
176        case DRM_SCHEME_WV_MODULAR:
177            return "WV Modular" ;
178
179#ifdef DRM_SCHEME_MCAST_SINK
180        case DRM_SCHEME_MCAST_SINK:
181            return "MCast Sink" ;
182#endif
183
184#ifdef DRM_SCHEME_PLAYREADY_ASF
185        case DRM_SCHEME_PLAYREADY_ASF:
186            return "PlayReady/ASF" ;
187#endif
188
189        default:
190            return "unknown" ;
191    }
192}
193// End of DrmSchemeToString()
194
195static void DumpBuffer2(const char* prefix, const uint8_t* start, uint32_t size)
196{
197    if (start == NULL || size == 0)
198    {
199        LOGV("Error: invalid parameters to %s", __FUNCTION__) ;
200        return ;
201    }
202
203    if (prefix == NULL)
204    {
205        prefix = "" ;
206    }
207
208    const uint32_t STR_SIZE = 1024 ;
209    char str[STR_SIZE] = {0} ;
210
211    DumpBufferToString(str, STR_SIZE, start, size) ;
212
213    LOGV("%s%s" DUMP_EOL, prefix, str) ;
214}
215// End of DumpBuffer2()
216
217static void DumpProtectedDataBuffer(const char* prefix, ProtectedDataBuffer* buf)
218{
219    if (buf == NULL)
220    {
221        LOGV("Error: invalid parameters to %s", __FUNCTION__) ;
222        return ;
223    }
224
225    if (prefix == NULL) { prefix = "" ; }
226
227    const uint32_t MAX_BUFFER_DUMP_LENGTH = 32 ;
228
229    if (buf->magic != PROTECTED_DATA_BUFFER_MAGIC)
230    {
231        const uint8_t* p = (uint8_t*) &buf->magic ;
232        LOGV("%sWrong magic: %02x %02x %02x %02x" DUMP_EOL, prefix, p[0], p[1], p[2], p[3]) ;
233        return ;
234    }
235
236    LOGV("%smagic: ok, drmScheme: %u (%s), clear: %u, size: %u, num PES: %u" DUMP_EOL, prefix,
237        buf->drmScheme, DrmSchemeToString(buf->drmScheme), buf->clear, buf->size, buf->numPesBuffers) ;
238
239    if (buf->numPesBuffers == 0)
240    {
241        uint32_t dumpLength = log_helper_min(buf->size, MAX_BUFFER_DUMP_LENGTH) ;
242        DumpBuffer2("data: ", buf->data, dumpLength) ;
243    }
244    else
245    {
246        for (uint32_t i = 0; i < buf->numPesBuffers; ++i)
247        {
248            const uint32_t STR_SIZE = 1024 ;
249            char str[STR_SIZE] = {0} ;
250
251            uint32_t dumpLength = log_helper_min(buf->pesBuffers[i].pesSize, MAX_BUFFER_DUMP_LENGTH) ;
252
253            DumpBufferToString(str, STR_SIZE,
254                buf->data + buf->pesBuffers[i].pesDataOffset, dumpLength) ;
255
256            LOGV("PES %u: streamCounter: %u, inputCounter: %llu, offset: %u, size: %u, PES data: %s" DUMP_EOL,
257                i, buf->pesBuffers[i].streamCounter, buf->pesBuffers[i].inputCounter,
258                buf->pesBuffers[i].pesDataOffset, buf->pesBuffers[i].pesSize, str) ;
259        }
260    }
261}
262// End of DumpProtectedDataBuffer
263
264static void DumpVideoFrameInfo(frame_info_t* fInfo)
265{
266    if (fInfo == NULL)
267    {
268        LOGV("Error: invalid parameters to %s", __FUNCTION__) ;
269        return ;
270    }
271
272    LOGV("frame_info_t: data = %p, size = %u, num_nalus = %u", fInfo->data, fInfo->size, fInfo->num_nalus) ;
273
274    for (uint32_t i = 0; i < fInfo->num_nalus; ++i)
275    {
276        LOGV("nalu_info_t: type = %#x, offset = %u (%#x), data = %p, length = %u",
277            fInfo->nalus[i].type, fInfo->nalus[i].offset, fInfo->nalus[i].offset,
278            fInfo->nalus[i].data, fInfo->nalus[i].length) ;
279
280        if (fInfo->nalus[i].data != NULL && fInfo->nalus[i].length > 0)
281        {
282            DumpBuffer2("nalu_info_t::data: ", fInfo->nalus[i].data, fInfo->nalus[i].length) ;
283        }
284    }
285}
286// End of DumpVideoFrameInfo()
287
288#else
289
290// Avoid #ifdef around the dump code
291
292#define DumpBuffer(...)
293#define DumpBuffer2(...)
294#define DumpNaluHeaderBuffer(...)
295#define DumpProtectedDataBuffer(...)
296#define DumpVideoFrameInfo(...)
297
298#define DUMP_EOL
299
300#endif // LOG_NDEBUG == 0
301
302#endif // LOG_DUMP_HELPER_INCLUDED
303