Guest User

working ARDrone video capture example

a guest
Apr 20th, 2014
646
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.57 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdint.h>
  3.  
  4. #include <sys/socket.h>
  5. #include <sys/time.h>
  6. #include <netinet/in.h>
  7. #include <netdb.h>
  8. #include <arpa/inet.h>
  9. #include <fcntl.h>
  10.  
  11. #include <SDL2/SDL.h>
  12.  
  13. #define DRONE_IP_ADDR "192.168.1.1"
  14. #define DRONE_VID_STREAM_PORT "5555"
  15.  
  16. extern "C" {
  17. #include <libavcodec/avcodec.h>
  18. #include <libswscale/swscale.h>
  19. #include <libavformat/avformat.h>
  20. }
  21.  
  22. #define VIDEO_BUFFER_SIZE 40000
  23. #define PaVE_HEADER_LENGTH 68
  24.  
  25. // Time collection globals
  26. double payload_time = 0;
  27. double decoder_time = 0;
  28. double converter_time = 0;
  29. double gui_time = 0;
  30.  
  31.  
  32. typedef struct { //PaVE
  33. uint8_t signature[4]; /* "PaVE" - used to identify the start of
  34.  frame */
  35. uint8_t version; /* Version code */
  36. uint8_t video_codec; /* Codec of the following frame */
  37. uint16_t header_size; /* Size of the parrot_video_encapsulation_t */
  38. uint32_t payload_size; /* Amount of data following this PaVE */
  39. uint16_t encoded_stream_width; /* ex: 640 */
  40. uint16_t encoded_stream_height; /* ex: 368 */
  41. uint16_t display_width; /* ex: 640 */
  42. uint16_t display_height; /* ex: 360 */
  43. uint32_t frame_number; /* Frame position inside the current stream
  44.  */
  45. uint32_t timestamp; /* In milliseconds */
  46. uint8_t total_chuncks; /* Number of UDP packets containing the
  47.  current decodable payload - currently unused */
  48. uint8_t chunck_index; /* Position of the packet - first chunk is #0
  49.  - currenty unused*/
  50. uint8_t frame_type; /* I-frame, P-frame -
  51.  parrot_video_encapsulation_frametypes_t */
  52. uint8_t control; /* Special commands like end
  53.     -of-stream or
  54.     advertised frames */
  55.     uint32_t stream_byte_position_lw; /* Byte position of the current payload in
  56.      the encoded stream - lower 32-bit word */
  57.     uint32_t stream_byte_position_uw; /* Byte position of the current payload in
  58.      the encoded stream - upper 32-bit word */
  59.     uint16_t stream_id; /* This ID indentifies packets that should be
  60.      recorded together */
  61.     uint8_t total_slices; /* number of slices composing the current
  62.      frame */
  63.     uint8_t slice_index; /* position of the current slice in the frame
  64.      */
  65.     uint8_t header1_size; /* H.264 only : size of SPS inside payload -
  66.      no SPS present if value is zero */
  67.     uint8_t header2_size; /* H.264 only : size of PPS inside payload -
  68.      no PPS present if value is zero */
  69.     uint8_t reserved2[2]; /* Padding to align on 48 bytes */
  70.     uint32_t advertised_size; /* Size of frames announced as advertised
  71.      frames */
  72.     uint8_t reserved3[12]; /* Padding to align on 64 bytes */
  73.     uint8_t reserved4[4]; // padding -- added b/c it was in the KIPR library code
  74. }__attribute__ ((packed)) parrot_video_encapsulation_t;
  75.  
  76. typedef enum { //PaVE codec IDs
  77.     CODEC_UNKNNOWN = 0,
  78.     CODEC_VLIB,
  79.     CODEC_P264,
  80.     CODEC_MPEG4_VISUAL,
  81.     CODEC_MPEG4_AVC
  82. } parrot_video_encapsulation_codecs_t;
  83.  
  84. typedef enum { //PaVE frame types
  85.     FRAME_TYPE_UNKNNOWN = 0, FRAME_TYPE_IDR_FRAME, /* headers followed by I-frame */
  86.     FRAME_TYPE_I_FRAME, FRAME_TYPE_P_FRAME, FRAME_TYPE_HEADERS
  87. } parrot_video_encapsulation_frametypes_t;
  88.  
  89. void printPaVE(parrot_video_encapsulation_t PaVE) {
  90.     printf("\n---------------------------\n");
  91.  
  92.     printf("Codec : %s\n",
  93.             (PaVE.video_codec == CODEC_MPEG4_VISUAL) ?
  94.                     "MP4" :
  95.                     ((PaVE.video_codec == CODEC_MPEG4_AVC) ? "H264" : "Unknown"));
  96.  
  97.     printf("StreamID : %d \n", PaVE.stream_id);
  98.     printf("Timestamp : %d ms\n", PaVE.timestamp);
  99.     printf("Encoded dims : %d x %d\n", PaVE.encoded_stream_width,
  100.             PaVE.encoded_stream_height);
  101.     printf("Display dims : %d x %d\n", PaVE.display_width, PaVE.display_height);
  102.     ////printf ("Header size  : %d (PaVE size : %d)\n", PaVE.header_size, sizeof (parrot_video_encapsulation_t));
  103.     printf("Header size : %d\n", PaVE.header_size);
  104.     printf("Payload size : %d\n", PaVE.payload_size);
  105.     printf("Size of SPS inside payload : %d\n", PaVE.header1_size);
  106.     printf("Size of PPS inside payload : %d\n", PaVE.header2_size);
  107.     printf("Slices in the frame : %d\n", PaVE.total_slices);
  108.     printf("Frame Type / Number : %s : %d : slide %d/%d\n",
  109.             (PaVE.frame_type == FRAME_TYPE_P_FRAME) ?
  110.                     "P-Frame" :
  111.                     ((PaVE.frame_type == FRAME_TYPE_I_FRAME) ?
  112.                             "I-Frame" : "IDR-Frame"), PaVE.frame_number,
  113.             PaVE.slice_index + 1, PaVE.total_slices);
  114.  
  115.     printf("---------------------------\n\n");
  116. }
  117.  
  118. int receive(int socketNumber, unsigned char *buffer, int requestSize) {
  119.     int lengthReceived = -1;
  120.     lengthReceived = recv(socketNumber, buffer, requestSize, 0);
  121.     if (lengthReceived < 0) {
  122.         printf("failed to receive assumed PaVE packet\n");
  123.     } else {
  124.         printf("asked for %i bytes, received packet of %i bytes\n", requestSize,
  125.                 lengthReceived);
  126.     }
  127.     return lengthReceived;
  128. }
  129.  
  130. void fetch_and_decode(int socketNumber,AVCodecContext *codecContext, AVFrame *picture) {
  131.  
  132.     double t = clock();
  133.  
  134.     parrot_video_encapsulation_t PaVE;
  135.     unsigned char part[VIDEO_BUFFER_SIZE];
  136.     int partLength = -1;
  137.     partLength = receive(socketNumber, part, VIDEO_BUFFER_SIZE);
  138.     if (partLength < 0) {
  139.         printf("did not receive video data\n");
  140.         return;
  141.     }
  142.  
  143.     memcpy(&PaVE, part, sizeof(parrot_video_encapsulation_t));
  144.  
  145.     if (strncmp((const char*) PaVE.signature, "PaVE", 4) != 0) {
  146.         printf("PaVE not synchronized, skipping iteration\n");
  147.         return;
  148.     } else {
  149.         printf("PaVE synchronized. YIPEEEEEEEEEEEEEEEEEEEEEEEE\n");
  150.         printPaVE(PaVE);
  151.     }
  152.  
  153.     uint32_t read = 0;
  154.     unsigned char payload[VIDEO_BUFFER_SIZE];
  155.  
  156.     memcpy(payload, part + PaVE.header_size, partLength - PaVE.header_size);
  157.     read += partLength - PaVE.header_size;
  158.  
  159.     double lastTime = clock();
  160.  
  161.  
  162.     while (read < PaVE.payload_size && (clock() - lastTime) < 0.1) {
  163.         int payloadLength = -1;
  164.         printf("gathering payload...\n");
  165.         payloadLength = receive(socketNumber, payload + read,
  166.                 PaVE.payload_size - read);
  167.         read += payloadLength;
  168.         lastTime = clock();
  169.     }
  170.  
  171.     if (read < PaVE.payload_size) {
  172.         return; // if the while loop times out before a full frame, need to exit
  173.     }
  174.  
  175.     payload_time += clock() - t;
  176.  
  177.     printf("payload complete, attempting to decode frame\n");
  178.  
  179.     AVPacket avPkt;
  180.     av_init_packet(&avPkt);
  181.     avPkt.data = NULL;
  182.     avPkt.size = 0;
  183.  
  184.     avPkt.data = payload;
  185.     avPkt.size = PaVE.payload_size;
  186.  
  187.     printf("avPkt.size = %d\n",avPkt.size);
  188.  
  189.     int done = 0;
  190.     int ret = -1;
  191.  
  192.     t = clock();
  193.  
  194.     ret = avcodec_decode_video2(codecContext, picture, &done, &avPkt);
  195.  
  196.     decoder_time += clock() - t;
  197.  
  198.     avPkt.data = NULL;
  199.     avPkt.size = 0;
  200.     av_free_packet(&avPkt);
  201.  
  202.     if (done == 0 || ret < 0) {
  203.         printf("could not decode frame\n");
  204.         return;
  205.     }
  206.  
  207.  
  208. }
  209.  
  210. ///////////////////////////////////////////////////////////////////////
  211. ///////////////////////////////////////////////////////////////////////
  212. ///////////////////////////////////////////////////////////////////////
  213.  
  214. int main() {
  215.  
  216.     if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  217.         fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
  218.         return -1;
  219.     }
  220.  
  221.     printf("\n\n*********************** START ***********************\n\n");
  222.  
  223.     printf("size of PaVE = %d\n",sizeof(parrot_video_encapsulation_t));
  224.  
  225.     int socketNumber;
  226.     sockaddr_in myAddr;
  227.     sockaddr_in droneAddr;
  228.  
  229.     // my sockaddr_in
  230.     myAddr.sin_family = AF_INET;
  231.     myAddr.sin_addr.s_addr = INADDR_ANY; // my IP address
  232.     myAddr.sin_port = htons(atoi(DRONE_VID_STREAM_PORT));
  233.  
  234.     // the drone's sockaddr_in
  235.     droneAddr.sin_family = AF_INET;
  236.     droneAddr.sin_addr.s_addr = inet_addr(DRONE_IP_ADDR);
  237.     droneAddr.sin_port = htons(atoi(DRONE_VID_STREAM_PORT));
  238.  
  239.     socketNumber = socket(AF_INET, SOCK_STREAM, 0);
  240.  
  241.     // bind the socket
  242.     if (bind(socketNumber, (sockaddr*) &myAddr, sizeof(sockaddr_in)) < 0) {
  243.         printf("failed to bind socket\n");
  244.     }
  245.  
  246.     int result = -1;
  247.     result = connect(socketNumber, (sockaddr*) &droneAddr, sizeof(sockaddr_in));
  248.     if (result != 0) {
  249.         printf("connection NOT established\n");
  250.     }
  251.  
  252.     printf("booting...\n");
  253.     // send one packet of "some bytes" to drone
  254.     uint8_t gateKeyPkt[4] = { 0x01, 0x00, 0x00, 0x00 };
  255.     int badCheck = -1;
  256.     badCheck = sendto(socketNumber, (void*) gateKeyPkt, 4, 0,
  257.             (sockaddr*) &droneAddr, sizeof(sockaddr_in));
  258.  
  259.     if (badCheck < 0) {
  260.         printf("Failed to send basic packet\n");
  261.     }
  262.  
  263.     AVCodec *codec = NULL;
  264.     AVCodecContext *codecContext = NULL;
  265.     AVFrame *picture = NULL;
  266.     AVFrame *pictureRGB = NULL;
  267.     AVFrame *pictureYUV = NULL;
  268.     SwsContext *convertContext_RGB = NULL;
  269.     SwsContext *convertContext_YUV = NULL;
  270.  
  271.     uint8_t *buffer_RGB = NULL;
  272.     uint8_t *buffer_YUV = NULL;
  273.  
  274.     // set up codec
  275.     avcodec_register_all();
  276.     av_register_all();
  277.     av_log_set_level(AV_LOG_DEBUG);
  278.     codec = avcodec_find_decoder(CODEC_ID_H264);
  279.     codec->id = CODEC_ID_H264;
  280.  
  281.     // set up codecContext
  282.     codecContext = avcodec_alloc_context3(codec);
  283.     avcodec_open2(codecContext, codec, 0);
  284.     codecContext->width = 640;
  285.     codecContext->height = 360;
  286.     codecContext->pix_fmt = PIX_FMT_YUV420P;
  287.     codecContext->skip_frame = AVDISCARD_DEFAULT;
  288.     codecContext->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
  289.     codecContext->skip_loop_filter = AVDISCARD_DEFAULT;
  290.     codecContext->workaround_bugs = FF_BUG_AUTODETECT;
  291.     codecContext->debug = true;
  292.  
  293.     // allocate video frames and buffer
  294.     picture = avcodec_alloc_frame();
  295.     pictureRGB = avcodec_alloc_frame();
  296.     pictureYUV = avcodec_alloc_frame();
  297.  
  298.     if (pictureYUV == NULL) {
  299.         printf("Could not allocate YUV frame\n");
  300.         return -1;
  301.     }
  302.  
  303.     int RGB_size = avpicture_get_size(PIX_FMT_RGB24, codecContext->width,codecContext->height);
  304.     int YUV_size = avpicture_get_size(PIX_FMT_YUV420P, codecContext->width,codecContext->height);
  305.     buffer_RGB = (uint8_t*) av_malloc(RGB_size* sizeof(uint8_t));
  306.     buffer_YUV = (uint8_t*) av_malloc(YUV_size* sizeof(uint8_t));
  307.  
  308.     // assign parts of buffer to image planes in RGB frame
  309.     avpicture_fill((AVPicture*) pictureRGB, buffer_RGB, PIX_FMT_RGB24,
  310.             codecContext->width, codecContext->height);
  311.     avpicture_fill((AVPicture*) pictureYUV, buffer_YUV, PIX_FMT_YUV420P,
  312.             codecContext->width, codecContext->height);
  313.  
  314.     // convert context
  315.     convertContext_RGB = sws_getContext(codecContext->width, codecContext->height,
  316.             codecContext->pix_fmt, codecContext->width, codecContext->height,
  317.             PIX_FMT_RGB24, SWS_SPLINE, 0, 0, 0);
  318.     convertContext_YUV = sws_getContext(codecContext->width, codecContext->height,
  319.             codecContext->pix_fmt, codecContext->width, codecContext->height,
  320.             PIX_FMT_YUV420P, SWS_SPLINE, NULL, NULL, NULL);
  321.  
  322.     //SDL stuff
  323.  
  324.     SDL_Window *window;
  325.     SDL_Renderer *render;
  326.     SDL_Texture *bmpTexture;
  327.     uint8_t *pixels;
  328.     int pitch;
  329.     int size;
  330.     // allocate window, renderer, texture
  331.     window = SDL_CreateWindow("YUV",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,
  332.                               codecContext->width,codecContext->height,SDL_WINDOW_SHOWN);
  333.     render = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
  334.     bmpTexture = SDL_CreateTexture(render,SDL_PIXELFORMAT_YV12,SDL_TEXTUREACCESS_STREAMING,
  335.                                    codecContext->width,codecContext->height);
  336.     size = codecContext->width*codecContext->height;
  337.     if ((window == NULL) | (render == NULL) | (bmpTexture == NULL)) {
  338.         printf("Could not open SDL window\n");
  339.         return -1;
  340.     }
  341.  
  342.     for (int j = 0; j < 1000; j++) {
  343.         fetch_and_decode(socketNumber, codecContext, picture);
  344.  
  345.         double t = clock();
  346.  
  347.         sws_scale(convertContext_YUV,
  348.                   picture->data,
  349.                   picture->linesize,
  350.                   0,
  351.                   codecContext->height,
  352.                   pictureYUV->data,
  353.                   pictureYUV->linesize);
  354.  
  355.         converter_time += clock() - t;
  356.  
  357.         //memcpy's hardcoded for YUV only!!!
  358.         SDL_LockTexture(bmpTexture,NULL,(void**)&pixels,&pitch);
  359.         memcpy(pixels,pictureYUV->data[0],size);
  360.         memcpy(pixels+size,pictureYUV->data[2],size/4);
  361.         memcpy(pixels+size*5/4,pictureYUV->data[1],size/4);
  362.         SDL_UnlockTexture(bmpTexture);
  363.         SDL_UpdateTexture(bmpTexture,NULL,pixels,pitch);
  364.         SDL_RenderClear(render);
  365.         SDL_RenderCopy(render,bmpTexture,NULL,NULL);
  366.         SDL_RenderPresent(render);
  367.  
  368.     }
  369.  
  370.     avcodec_close(codecContext);
  371.     av_free(codecContext);
  372.     av_free(picture);
  373.     av_free(pictureRGB);
  374.     av_free(buffer_RGB);
  375.     av_free(buffer_YUV);
  376.     av_free(pictureYUV);
  377.     sws_freeContext(convertContext_RGB);
  378.     sws_freeContext(convertContext_YUV);
  379.  
  380.     double payload_time_avg = payload_time / 1000./CLOCKS_PER_SEC;
  381.     double decoder_time_avg = decoder_time / 1000./CLOCKS_PER_SEC;
  382.     double converter_time_avg = converter_time / 1000./CLOCKS_PER_SEC;
  383.  
  384.     printf("Average time per payload = %f seconds\n",payload_time_avg);
  385.     printf("Average time per decode = %f seconds\n",decoder_time_avg);
  386.     printf("Average time per conversion = %f seconds\n",converter_time_avg);
  387.  
  388.     return 1;
  389. }
Advertisement
Add Comment
Please, Sign In to add comment