UVCAndroid

repository·main·Indexed 19 days ago

https://github.com/shiyinghan/uvcandroid

A library and sample project that enables non-rooted Android devices (Android 5.0+) to access UVC (USB Video Class) cameras. It provides the CameraConnectionService for managing USB device lifecycles, permission requests, and camera operations including preview, image capture, and video recording. The project incorporates native components such as libuvc for camera communication, libjpeg-turbo for JPEG processing, and RapidJSON for JSON parsing.

Tokens
35.8K
Snippets
125
Records
163
Agent score
67%

What's inside UVCAndroid

  1. Overview of RapidJSON stream types

    main

    RapidJSON provides several specialized stream classes to optimize JSON parsing and generation depending on the data source:

    • Memory Streams: Simple streams for handling data in memory (e.g., StringBuffer for output, StringStream for input).
    • File Streams: Reduces memory footprint by reading/writing directly to the file system (e.g., FileReadStream for input, FileWriteStream for output).
    • Encoded Streams: Handles conversion between byte streams and character streams (e.g., EncodedInputStream, EncodedOutputStream, AutoUTFInputStream, AutoUTFOutputStream).
    • Custom Streams: Users can implement their own stream interface to wrap existing objects or custom logic.
  2. Filter JSON content using intermediate SAX handlers

    main

    You can create intermediate layers between a Reader and a Writer to transform or filter JSON data on the fly. This allows for tasks like removing whitespace (condensing), reformatting (pretty printing), or modifying values (e.g., capitalizing strings) without ever building a DOM.

    Implementation Pattern:

    1. Create a filter struct that implements the SAX handler interface.
    2. The filter's methods should perform the desired transformation.
    3. The filter then calls the corresponding method on an underlying OutputHandler (usually a Writer or PrettyWriter).

    Note: Because SAX is event-based, you only see one piece of data at a time. If your filter requires context (like the current path from the root), you must manually track that state within your filter struct.

    template<typename OutputHandler>
    struct CapitalizeFilter {
        CapitalizeFilter(OutputHandler& out) : out_(out) {}
    
        bool String(const char* str, SizeType length, bool copy) {
            std::string upper_str;
            for (SizeType i = 0; i < length; i++) {
                upper_str.push_back(std::toupper(str[i]));
            }
            return out_.String(upper_str.c_str(), upper_str.length(), true);
        }
    
        // Forward all other events to the output handler...
        bool StartObject() { return out_.StartObject(); }
        bool EndObject(SizeType n) { return out_.EndObject(n); }
        // ... etc
    
        OutputHandler& out_;
    };
  3. Handle JSON strings with null characters

    main

    RapidJSON supports JSON strings containing the Unicode character U+0000 (escaped as "\u0000"). Because C/C++ strings are typically null-terminated, strlen() will return an incorrect length for such strings.

    To correctly handle these, use GetStringLength() to get the actual number of characters. This is also more efficient for buffer allocation.

    // If JSON is { "s" : "a\u0000b" }
    // strlen(document["s"].GetString()) would return 1
    // Use GetStringLength() for the correct value (3)
    size_t len = document["s"].GetStringLength();
  4. Query JSON values and types

    main

    Once parsed, you can query the Document or any Value object. Because a Value can hold different types, you should first verify the type using IsXXX() methods before calling GetXXX() to avoid undefined behavior or assertion failures.

    Common type checks and getters:

    • String: IsString() / GetString()
    • Boolean: IsBool() / GetBool()
    • Null: IsNull()
    • Number: IsNumber() / IsInt() / IsDouble() / etc.
    • Array: IsArray()
    • Object: IsObject()
    assert(document.HasMember("hello"));
    assert(document["hello"].IsString());
    printf("hello = %s\n", document["hello"].GetString());
  5. How up-sampling works in LibYuv

    main

    When up-sampling, the behavior varies significantly by filter:

    • Point up-sampling: Uses a stepping rate of src_width / dst_width and starts at coordinate x = 0. Each pixel is replicated by the scale factor.
    • Bilinear up-sampling: Stretches the image so the first and last source pixels map exactly to the first and last destination pixels. This is achieved using dx = (src_width - 1) / (dst_width - 1) and x = 0.
    • Box up-sampling: Switches to Bilinear filtering logic.
  6. Customize RapidJSON Document and Value templates

    main

    RapidJSON's Value and Document are typedefs of template classes. You can customize them by providing specific Encoding and Allocator parameters.

    • Encoding: Specifies how JSON strings are stored in memory (e.g., UTF8<>, UTF16<>, UTF32<>).
    • Allocator: Defines the memory management strategy. Document owns the allocator, while Value only references it.

    Commonly used typedefs:

    • Value: GenericValue<UTF8<>>
    • Document: GenericDocument<UTF8<>>
    namespace rapidjson {
    
    template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
    class GenericValue {
        // ...
    };
    
    template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
    class GenericDocument : public GenericValue<Encoding, Allocator> {
        // ...
    };
    
    typedef GenericValue<UTF8<> > Value;
    typedef GenericDocument<UTF8<> > Document;
    
    } // namespace rapidjson
  7. Understand core libyuv formats and conversion logic

    main

    libyuv relies on two core formats as conversion hubs:

    1. I420 (YUV): All YUV formats can be converted to or from I420.
    2. ARGB (RGB): All RGB formats can be converted to or from ARGB.

    When performing operations like scaling or planar functions, use these core formats. Most filtering functions (e.g., ARGBScale) are either channel-order agnostic or specifically designed for ARGB or I420.

  8. Understand LibYuv filtering modes and behavior

    main

    LibYuv implements several filtering modes for image scaling (up-sampling and down-sampling). The behavior of these filters depends on the FilterMode and whether you are scaling up or down.

    Filter Modes

    • Point: Takes the middle pixel (down-sampling) or replicates pixels (up-sampling). It is reversible and matches FFmpeg behavior.
    • Bilinear: Uses a 2x2 pixel neighborhood.
      • In down-sampling, it is considered correct and centered.
      • In up-sampling, it stretches the image such that the first source pixel maps to the first destination pixel and the last source pixel maps to the last destination pixel. This results in slight magnification.
    • Box: Averages the entire box.
      • In down-sampling, it is equivalent to bilinear for a 2x scale factor.
      • In up-sampling, the Box filter switches over to Bilinear behavior.
    • Linear: A variant of bilinear sampling used in specific scaling contexts.
  9. Understand ARGB layout and memory ordering

    main

    The FOURCC describes the order of channels in a register. On little-endian machines, the memory layout is the reverse of the register order.

    For FOURCC_ARGB:

    1. Register order: A, R, G, B.
    2. Memory order (Little Endian): B, G, R, A (Blue is the lowest byte).

    Important Note on Blending: When using ARGBBlend, the R, G, and B channels must be premultiplied by alpha (preattenuated). Other functions typically do not require this.

    /* The FOURCC macro reverses the order for little endian */
    #define FOURCC(a, b, c, d) (((uint32)(a)) | ((uint32)(b) << 8) | ((uint32)(c) << 16) | ((uint32)(d) << 24))
    
    /* Example: ARGB string read as uint32 */
    FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B');