[x265] [PATCH] y4m: make file reading threaded

kavitha at multicorewareinc.com kavitha at multicorewareinc.com
Tue Oct 15 10:45:46 CEST 2013


# HG changeset patch
# User Kavitha Sampath <kavitha at multicorewareinc.com>
# Date 1381825927 -19800
#      Tue Oct 15 14:02:07 2013 +0530
# Node ID 5a94d3e1d4fe769b8dca27f2a1c61784248adaff
# Parent  1a85d8814346efdb984ea9eae24d1b06b973e9a8
y4m: make file reading threaded

diff -r 1a85d8814346 -r 5a94d3e1d4fe source/input/input.h
--- a/source/input/input.h	Tue Oct 15 12:45:58 2013 +0530
+++ b/source/input/input.h	Tue Oct 15 14:02:07 2013 +0530
@@ -24,6 +24,14 @@
 #ifndef X265_INPUT_H
 #define X265_INPUT_H
 
+#define ENABLE_THREAD
+#define MIN_FRAME_WIDTH 64
+#define MAX_FRAME_WIDTH 8192
+#define MIN_FRAME_HEIGHT 64
+#define MAX_FRAME_HEIGHT 4320
+#define MIN_FRAME_RATE 1
+#define MAX_FRAME_RATE 300
+
 #include "x265.h"
 
 namespace x265 {
diff -r 1a85d8814346 -r 5a94d3e1d4fe source/input/y4m.cpp
--- a/source/input/y4m.cpp	Tue Oct 15 12:45:58 2013 +0530
+++ b/source/input/y4m.cpp	Tue Oct 15 14:02:07 2013 +0530
@@ -23,6 +23,7 @@
 
 #include "y4m.h"
 #include "PPA/ppa.h"
+#include "common.h"
 #include <stdio.h>
 #include <string.h>
 
@@ -32,25 +33,53 @@
 Y4MInput::Y4MInput(const char *filename)
 {
     ifs.open(filename, ios::binary | ios::in);
+    threadActive = false;
     if (!ifs.fail())
     {
-        parseHeader();
-        buf = new char[3 * width * height / 2];
+        if (parseHeader())
+        {
+            threadActive = true;
+#if defined(ENABLE_THREAD)
+            for (int i = 0; i < QUEUE_SIZE; i++)
+            {
+                buf[i] = new char[3 * width * height / 2];
+                if ( buf[i] == NULL)
+                {
+                    x265_log(NULL, X265_LOG_ERROR, "y4m: buffer allocation failure, aborting");
+                    threadActive = false;
+                }
+            }
+            head = 0;
+            tail = 0;
+            start();
+#else
+            buf = new char[3 * width * height / 2];
+#endif
+        }
     }
+    if (!threadActive)
+        ifs.close();
 }
 
 Y4MInput::~Y4MInput()
 {
     ifs.close();
+#if defined(ENABLE_THREAD)
+    for (int i = 0; i < QUEUE_SIZE; i++)
+    {
+        delete[] buf[i];
+    }
+#else
     delete[] buf;
+#endif
 }
 
-void Y4MInput::parseHeader()
+bool Y4MInput::parseHeader()
 {
-    int t_width = 0;
-    int t_height = 0;
-    int t_rateNumerator = 0;
-    int t_rateDenominator = 0;
+    int frame_width = 0;
+    int frame_height = 0;
+    int frame_rateNumerator = 0;
+    int frame_rateDenominator = 0;
 
     while (ifs)
     {
@@ -67,7 +96,7 @@
             switch (ifs.get())
             {
             case 'W':
-                t_width = 0;
+                frame_width = 0;
                 while (ifs)
                 {
                     byte = ifs.get();
@@ -78,14 +107,13 @@
                     }
                     else
                     {
-                        t_width = t_width * 10 + (byte - '0');
+                        frame_width = frame_width * 10 + (byte - '0');
                     }
                 }
-
                 break;
 
             case 'H':
-                t_height = 0;
+                frame_height = 0;
                 while (ifs)
                 {
                     byte = ifs.get();
@@ -95,21 +123,21 @@
                     }
                     else
                     {
-                        t_height = t_height * 10 + (byte - '0');
+                        frame_height = frame_height * 10 + (byte - '0');
                     }
                 }
 
                 break;
 
             case 'F':
-                t_rateNumerator = 0;
-                t_rateDenominator = 0;
+                frame_rateNumerator = 0;
+                frame_rateDenominator = 0;
                 while (ifs)
                 {
                     byte = ifs.get();
                     if (byte == '.')
                     {
-                        t_rateDenominator = 1;
+                        frame_rateDenominator = 1;
                         while (ifs)
                         {
                             byte = ifs.get();
@@ -119,8 +147,8 @@
                             }
                             else
                             {
-                                t_rateNumerator = t_rateNumerator * 10 + (byte - '0');
-                                t_rateDenominator = t_rateDenominator * 10;
+                                frame_rateNumerator = frame_rateNumerator * 10 + (byte - '0');
+                                frame_rateDenominator = frame_rateDenominator * 10;
                             }
                         }
 
@@ -136,14 +164,14 @@
                                 break;
                             }
                             else
-                                t_rateDenominator = t_rateDenominator * 10 + (byte - '0');
+                                frame_rateDenominator = frame_rateDenominator * 10 + (byte - '0');
                         }
 
                         break;
                     }
                     else
                     {
-                        t_rateNumerator = t_rateNumerator * 10 + (byte - '0');
+                        frame_rateNumerator = frame_rateNumerator * 10 + (byte - '0');
                     }
                 }
 
@@ -170,10 +198,16 @@
 
 //TODO need to include code for parsing colourspace from file.
 
-    width = t_width;
-    height = t_height;
-    rateNum = t_rateNumerator;
-    rateDenom = t_rateDenominator;
+    if (frame_width < MIN_FRAME_WIDTH || frame_width > MAX_FRAME_WIDTH ||
+        frame_height < MIN_FRAME_HEIGHT || frame_width > MAX_FRAME_HEIGHT ||
+        (frame_rateNumerator / frame_rateDenominator) < 1 || (frame_rateNumerator / frame_rateDenominator) > MAX_FRAME_RATE)
+        return false;
+
+    width = frame_width;
+    height = frame_height;
+    rateNum = frame_rateNumerator;
+    rateDenom = frame_rateDenominator;
+    return true;
 }
 
 static const char header[] = "FRAME";
@@ -199,6 +233,80 @@
     }
 }
 
+#if defined(ENABLE_THREAD)
+bool Y4MInput::readPicture(x265_picture_t& pic)
+{
+    PPAStartCpuEventFunc(read_yuv);
+    if (!threadActive)
+        return false;
+    while (head == tail)
+    {
+        notEmpty.wait();
+    }
+    if (!frameStat[head])
+        return false;
+
+    pic.planes[0] = buf[head];
+
+    pic.planes[1] = buf[head] + width * height;
+
+    pic.planes[2] = buf[head] + width * height + ((width * height) >> 2);
+
+    pic.bitDepth = 8;
+
+    pic.stride[0] = width;
+
+    pic.stride[1] = pic.stride[2] = pic.stride[0] >> 1;
+    head = (head + 1) % QUEUE_SIZE;
+    notFull.trigger();
+
+    PPAStopCpuEventFunc(read_yuv);
+    return true;
+}
+
+void Y4MInput::threadMain()
+{
+    do
+    {
+        if (!populateFrameQueue())
+            break;
+    }
+    while (threadActive);
+}
+
+bool Y4MInput::populateFrameQueue()
+{
+    /* strip off the FRAME header */
+    char hbuf[sizeof(header)];
+    ifs.read(hbuf, strlen(header));
+    if (!ifs || memcmp(hbuf, header, strlen(header)))
+    {
+        if (ifs)
+            x265_log(NULL, X265_LOG_ERROR, "y4m: frame header missing");
+        return false;
+    }
+    /* consume bytes up to line feed */
+    int byte = ifs.get();
+    while (byte != '\n' && !ifs)
+    {
+        byte = ifs.get();
+    }
+    const size_t count = width * height * 3 / 2;
+    while ((tail + 1) % QUEUE_SIZE == head)
+    {
+        notFull.wait();
+        if (!threadActive)
+            break;
+    }
+    ifs.read(buf[tail], count);
+    frameStat[tail] = ifs.good();
+    if (!frameStat[tail])
+        return false;
+    tail = (tail + 1) % QUEUE_SIZE;
+    notEmpty.trigger();
+    return true;
+}
+#else
 bool Y4MInput::readPicture(x265_picture_t& pic)
 {
     PPAStartCpuEventFunc(read_yuv);
@@ -206,9 +314,9 @@
     /* strip off the FRAME header */
     char hbuf[sizeof(header)];
     ifs.read(hbuf, strlen(header));
-    if (!ifs || strncmp(hbuf, header, strlen(header)))
+    if (!ifs || memcmp(hbuf, header, strlen(header)))
     {
-        fprintf(stderr, "Y4M frame header missing\n");
+        x265_log(NULL, X265_LOG_ERROR, "y4m: frame header missing");
         return false;
     }
 
@@ -238,3 +346,13 @@
 
     return ifs.good();
 }
+#endif
+void Y4MInput::release()
+{
+#if defined(ENABLE_THREAD)
+    threadActive = false;
+    notFull.trigger();
+    stop();
+#endif
+    delete this;
+}
diff -r 1a85d8814346 -r 5a94d3e1d4fe source/input/y4m.h
--- a/source/input/y4m.h	Tue Oct 15 12:45:58 2013 +0530
+++ b/source/input/y4m.h	Tue Oct 15 14:02:07 2013 +0530
@@ -27,10 +27,19 @@
 #include "input.h"
 #include <fstream>
 
+#if defined(ENABLE_THREAD)
+#define QUEUE_SIZE 5
+#include "threading.h"
+#endif
+
 namespace x265 {
 // x265 private namespace
 
+#if defined(ENABLE_THREAD)
+class Y4MInput : public Input, public Thread
+#else
 class Y4MInput : public Input
+#endif
 {
 protected:
 
@@ -42,11 +51,26 @@
 
     int height;
 
-    char* buf;
+    bool threadActive;
 
+#if defined(ENABLE_THREAD)
+    volatile int head;
+
+    volatile int tail;
+
+    bool frameStat[QUEUE_SIZE];
+
+    char* buf[QUEUE_SIZE];
+
+    Event notFull;
+
+    Event notEmpty;
+#else
+    char *buf;
+#endif
     std::ifstream ifs;
 
-    void parseHeader();
+    bool parseHeader();
 
 public:
 
@@ -66,9 +90,9 @@
 
     bool isEof() const                            { return ifs.eof(); }
 
-    bool isFail()                                 { return !ifs.is_open(); }
+    bool isFail()                                 { return !(ifs.is_open() && threadActive); }
 
-    void release()                                { delete this; }
+    void release();
 
     int  guessFrameCount();
 
@@ -76,6 +100,14 @@
 
     bool readPicture(x265_picture_t&);
 
+#if defined(ENABLE_THREAD)
+
+    void threadMain();
+
+    bool populateFrameQueue();
+
+#endif
+
     const char *getName() const                   { return "y4m"; }
 };
 }


More information about the x265-devel mailing list