// Our code is based on https://www.kernel.org/doc/html/v4.11/media/uapi/v4l/capture.c.html // You can replace process_image(const void *p, int size) in the above sample code with our void processImage(unsigned char *p, int size), which can process the motion detection features. #include #include #include #include uint8_t *prevFrameData = NULL; int frameNum = 0; // stores the number of frameNum the camera has seen so far int motion = 0; int prevMotion = -1; int firstFrame = 1; int stoppingMotionCount = 0; // counts number of frames since last motion frames // Method extracted from https://www.kernel.org/doc/html/v4.11/media/uapi/v4l/capture.c.html and then modified to meet our needs // For motion static void processImage(unsigned char *p, int size) { // fwrite(p, size, 1, stdout); // Instead of sending data to STDOUT, send data to the NodeJS server using UDP socket. // UDP_sendFrame(p, size); // Record_addFrame(p, size); // Create MJPEG codec AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); // Create the context AVCodecContext *codecContext = avcodec_alloc_context3(codec); // Open codec if (avcodec_open2(codecContext, codec, NULL) < 0) { printf("avcodec_open2 error\n"); exit(1); } // Take the mjpeg buffer data and put it in packet AVPacket packet; av_init_packet(&packet); packet.data = malloc(sizeof(unsigned char) * size); memcpy(packet.data, p, size); packet.size = size; // Send packet to avcodec to it can decode with the provided codec if (avcodec_send_packet(codecContext, &packet) < 0) { // Handle error printf("send packet error\n"); exit(1); } // Alloc frame AVFrame *frame = av_frame_alloc(); // Receive the frame from avocdec and now we have the decoded data! if (avcodec_receive_frame(codecContext, frame) < 0) { printf("receive frame error\n"); exit(1); } uint8_t *frameData = frame->data[0]; // grab data from one channel, because we don't care for color. This channel should be red channel int frameDataSize = frame->linesize[0] * frame->height; // get size if (prevFrameData == NULL) { prevFrameData = malloc(sizeof(uint8_t) * frameDataSize); // if no previous frame, alloc space for storing previous frame } else { /* THE MOTION DECTION STEP. Essentially, it will check if 10% of the pixels differ by more than THRESHOLD amount of rgb value */ int differentPixels = 0; for (int i = 0; i < frameDataSize; ++i) { uint8_t prevPixel = prevFrameData[i]; uint8_t curPixel = frameData[i]; int diff = (int)((int)curPixel) - ((int)prevPixel); // get different diff = diff < 0 ? diff * -1 : diff; // get abs // check diff if (diff > THRESHOLD) { differentPixels++; } } // if more than 5% of pixels are different then motion! if (differentPixels >= frameDataSize * 0.05) { motion++; stoppingMotionCount = 0; } else { motion--; stoppingMotionCount++; if (stoppingMotionCount == STOP_RECORDING_THRESHOLD) { motion = 1; // next frame it will stop } if (motion < 0) { motion = 0; } } if (firstFrame != 0) { if (motion == 1 && prevMotion < 1) { // motion has begun! // Record_markStart(); // Buzzer_enableBuzz(); // led_start(); } if (prevMotion > 0 && motion == 0) { // motion has ended! // Record_markEnd(); // Buzzer_disableBuzz(); // led_stop(); } } fprintf(stderr, "\n------------------------\nFrame: %d\nMotion:%d\n--------------------\n", frameNum, motion); prevMotion = motion; firstFrame = 1; } // set current frame as prevFrame, so it can be prevFrame for the next frame. memcpy(prevFrameData, frameData, frameDataSize); // close stuff avcodec_free_context(&codecContext); av_frame_free(&frame); frameNum++; // increment the count of frameNum dealt with. fflush(stderr); fprintf(stderr, "."); fflush(stdout); }