Advertisement
GeeckoDev

vcat 0.0001

May 2nd, 2012
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.54 KB | None | 0 0
  1. /*
  2. vcat -- Outputs a video on a 256-color enabled terminal with UTF-8 locale
  3. Andreas Textor <textor.andreas@googlemail.com>
  4. Clément Guérin <geecko.dev@free.fr>
  5.  
  6. Copyright 2010 Andreas Textor. All rights reserved.
  7. Copyright 2012 Clément Guérin. All rights reserved.
  8.  
  9. Redistribution and use in source and binary forms, with or without modification, are
  10. permitted provided that the following conditions are met:
  11.  
  12.    1. Redistributions of source code must retain the above copyright notice, this list of
  13.       conditions and the following disclaimer.
  14.  
  15.    2. Redistributions in binary form must reproduce the above copyright notice, this list
  16.       of conditions and the following disclaimer in the documentation and/or other materials
  17.       provided with the distribution.
  18.  
  19. THIS SOFTWARE IS PROVIDED BY Clément Guérin ``AS IS'' AND ANY EXPRESS OR IMPLIED
  20. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  21. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andreas Textor OR
  22. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  25. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  26. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  27. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <stdint.h>
  34. #include <getopt.h>
  35. #include <malloc.h>
  36. #include <unistd.h>
  37. #include <libavcodec/avcodec.h>
  38. #include <libavformat/avformat.h>
  39.  
  40. #define VERSION "0.1"
  41.  
  42. static uint32_t colors[] = {
  43.     // Colors 0 to 15: original ANSI colors
  44.     0x000000, 0xcd0000, 0x00cd00, 0xcdcd00, 0x0000ee, 0xcd00cd, 0x00cdcd, 0xe5e5e5,
  45.     0x7f7f7f, 0xff0000, 0x00ff00, 0xffff00, 0x5c5cff, 0xff00ff, 0x00ffff, 0xffffff,
  46.     // Color cube colors
  47.     0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
  48.     0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af,
  49.     0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
  50.     0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
  51.     0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
  52.     0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
  53.     0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
  54.     0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
  55.     0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
  56.     0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
  57.     0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af,
  58.     0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
  59.     0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
  60.     0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
  61.     0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
  62.     0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
  63.     0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
  64.     0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
  65.     0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
  66.     0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af,
  67.     0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
  68.     0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
  69.     0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af,
  70.     0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
  71.     0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
  72.     0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
  73.     0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
  74.     // >= 233: Grey ramp
  75.     0x000000, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
  76.     0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
  77.     0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada,
  78. };
  79.  
  80. // Find an xterm color value that matches an ARGB color
  81. uint8_t rgb2xterm(uint32_t* pixel) {
  82.     uint8_t c, match = 0;
  83.     uint32_t r, g, b, d, distance;
  84.  
  85.     distance = 0xFFFFFFFF;
  86.     for(c = 0; c <= 253; c++) {
  87.         r = ((0xff0000 & colors[c]) >> 16) - ((0xff0000 & *pixel) >> 16);
  88.         g = ((0x00ff00 & colors[c]) >> 8)  - ((0x00ff00 & *pixel) >> 8 );
  89.         b =  (0x0000ff & colors[c])        -  (0x0000ff & *pixel);
  90.         d = r * r + g * g + b * b;
  91.         if (d < distance) {
  92.             distance = d;
  93.             match = c;
  94.         }
  95.     }
  96.  
  97.     return match;
  98. }
  99.  
  100. void print_usage() {
  101.     printf("vcat (" VERSION ") outputs a video on a 256-color enabled terminal with UTF-8 locale.\n"
  102.             "Usage: vcat [-h|--help] videofile\n"
  103.             "   -h | --help  -- Display this message\n"
  104.             "   videofile    -- The image to print.\n");
  105. }
  106.  
  107. int getNextFrame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx,
  108.     int videoStream, AVFrame *pFrame)
  109. {
  110.     static AVPacket packet;
  111.     static int      bytesRemaining=0;
  112.     static uint8_t  *rawData;
  113.     static int      fFirstTime=1;
  114.     int             bytesDecoded;
  115.     int             frameFinished;
  116.  
  117.     // First time we're called, set packet.data to NULL to indicate it
  118.     // doesn't have to be freed
  119.     if(fFirstTime)
  120.     {
  121.         fFirstTime=0;
  122.         packet.data=NULL;
  123.     }
  124.  
  125.     // Decode packets until we have decoded a complete frame
  126.     while(1)
  127.     {
  128.         // Work on the current packet until we have decoded all of it
  129.         while(bytesRemaining > 0)
  130.         {
  131.             // Decode the next chunk of data
  132.             bytesDecoded=avcodec_decode_video2(pCodecCtx, pFrame,
  133.                 &frameFinished, &packet);
  134.  
  135.             // Was there an error?
  136.             if(bytesDecoded < 0)
  137.             {
  138.                 fprintf(stderr, "Error while decoding frame\n");
  139.                 return 0;
  140.             }
  141.  
  142.             bytesRemaining-=bytesDecoded;
  143.             rawData+=bytesDecoded;
  144.  
  145.             // Did we finish the current frame? Then we can return
  146.             if(frameFinished)
  147.                 return 1;
  148.         }
  149.  
  150.         // Read the next packet, skipping all packets that aren't for this
  151.         // stream
  152.         do
  153.         {
  154.             // Free old packet
  155.             if(packet.data!=NULL)
  156.                 av_free_packet(&packet);
  157.  
  158.             // Read new packet
  159.             if(av_read_packet(pFormatCtx, &packet)<0)
  160.                 goto loop_exit;
  161.         } while(packet.stream_index!=videoStream);
  162.  
  163.         bytesRemaining=packet.size;
  164.         rawData=packet.data;
  165.     }
  166.  
  167. loop_exit:
  168.  
  169.     // Decode the rest of the last frame
  170.     bytesDecoded=avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,
  171.         &packet);
  172.  
  173.     // Free last packet
  174.     if(packet.data!=NULL)
  175.         av_free_packet(&packet);
  176.  
  177.     return frameFinished!=0;
  178. }
  179.  
  180. void printFrame(AVFrame *pFrame, AVCodecContext *pCodecCtx)
  181. {
  182.     uint8_t *p;
  183.     uint8_t col1, col2;
  184.     uint32_t sx, sy;
  185.     uint32_t pixel;
  186.  
  187.     // Clear the terminal the ugly way
  188.     system("clear");
  189.  
  190.     for (int h = 0; h < 48; h += 2) {
  191.         // Draw a horizontal line. Each console line consists of two
  192.         // pixel lines in order to keep the pixels square (most console
  193.         // fonts have two times the height for the width of each character)
  194.         for (int w = 0; w < 80; w++) {
  195.             sx = w * pCodecCtx->width / 80;
  196.  
  197.             sy = (h+1) * pCodecCtx->height / 48;
  198.             p = pFrame->data[0] + sy*pFrame->linesize[0] + sx;
  199.             pixel = (p[0] & 0xFF) << 16 |
  200.                     (p[1] & 0xFF) << 8  |
  201.                     (p[2] & 0xFF);
  202.             col1 = rgb2xterm(&pixel);
  203.  
  204.             sy = h * pCodecCtx->height / 48;
  205.             p = pFrame->data[0] + sy*pFrame->linesize[0] + sx;
  206.             pixel = (p[0] & 0xFF) << 16 |
  207.                     (p[1] & 0xFF) << 8  |
  208.                     (p[2] & 0xFF);
  209.             col2 = rgb2xterm(&pixel);
  210.  
  211.             printf("\x1b[38;5;%dm\x1b[48;5;%dm▄", col1, col2);
  212.         }
  213.         printf("\x1b[0m\n");
  214.     }
  215. }
  216.  
  217. int main(int argc, char* argv[]) {
  218.     static int      display_help = 0;
  219.     int             c;
  220.     int             i;
  221.     AVFormatContext *pFormatCtx;
  222.     int             videoStream;
  223.     AVCodecContext  *pCodecCtx;
  224.     AVCodec         *pCodec;
  225.     AVFrame         *pFrame;
  226.     AVFrame         *pFrameRGB;
  227.     int             numBytes;
  228.     uint8_t         *buffer;
  229.  
  230.     for(;;) {
  231.         static struct option long_options[] = {
  232.             {"h",    no_argument,       &display_help, 1},
  233.             {0, 0, 0, 0}
  234.         };
  235.  
  236.         c = getopt_long (argc, argv, "h", long_options, NULL);
  237.  
  238.         if (c == -1)
  239.             break;
  240.  
  241.         switch (c) {
  242.             case 'h':
  243.                 display_help = 1;
  244.  
  245.             case '?':
  246.                 break;
  247.  
  248.             default:
  249.                 abort();
  250.         }
  251.     }
  252.  
  253.     if (display_help == 1 || optind == argc || optind < argc - 1) {
  254.         print_usage();
  255.         exit(0);
  256.     }
  257.  
  258.     // Register all formats and codecs
  259.     av_register_all();
  260.  
  261.     // Open video file
  262.     if(av_open_input_file(&pFormatCtx, argv[optind], NULL, 0, NULL)!=0)
  263.         return -1; // Couldn't open file
  264.  
  265.     // Retrieve stream information
  266.     if(av_find_stream_info(pFormatCtx)<0)
  267.         return -1; // Couldn't find stream information
  268.  
  269.     // Dump information about file onto standard error
  270.     dump_format(pFormatCtx, 0, argv[1], 0);
  271.  
  272.     // Find the first video stream
  273.     videoStream=-1;
  274.     for(i=0; i<pFormatCtx->nb_streams; i++)
  275.         if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
  276.         {
  277.             videoStream=i;
  278.             break;
  279.         }
  280.     if(videoStream==-1)
  281.         return -1; // Didn't find a video stream
  282.  
  283.     // Get a pointer to the codec context for the video stream
  284.     pCodecCtx=pFormatCtx->streams[videoStream]->codec;
  285.  
  286.     // Find the decoder for the video stream
  287.     pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
  288.     if(pCodec==NULL)
  289.         return -1; // Codec not found
  290.  
  291.     // Inform the codec that we can handle truncated bitstreams -- i.e.,
  292.     // bitstreams where frame boundaries can fall in the middle of packets
  293.     if(pCodec->capabilities & CODEC_CAP_TRUNCATED)
  294.         pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
  295.  
  296.     // Open codec
  297.     if(avcodec_open(pCodecCtx, pCodec)<0)
  298.         return -1; // Could not open codec
  299.  
  300.     // Allocate video frame
  301.     pFrame=avcodec_alloc_frame();
  302.  
  303.     // Allocate an AVFrame structure
  304.     pFrameRGB=avcodec_alloc_frame();
  305.     if(pFrameRGB==NULL)
  306.         return -1;
  307.  
  308.     // Determine required buffer size and allocate buffer
  309.     numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
  310.         pCodecCtx->height);
  311.     buffer=malloc(numBytes*sizeof(uint8_t));
  312.  
  313.     // Assign appropriate parts of buffer to image planes in pFrameRGB
  314.     avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
  315.         pCodecCtx->width, pCodecCtx->height);
  316.  
  317.     while(getNextFrame(pFormatCtx, pCodecCtx, videoStream, pFrame))
  318.     {
  319.         //img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame,
  320.         //    pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
  321.            
  322.         printFrame(pFrame, pCodecCtx);
  323.     }
  324.    
  325.     // Free the RGB image
  326.     free(buffer);
  327.     av_free(pFrameRGB);
  328.  
  329.     // Free the YUV frame
  330.     av_free(pFrame);
  331.  
  332.     // Close the codec
  333.     avcodec_close(pCodecCtx);
  334.  
  335.     // Close the video file
  336.     av_close_input_file(pFormatCtx);
  337.  
  338.     return 0;
  339. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement