Use a .tiff file as input rather than an artificial image.
[j2kbench.git] / j2kbench.cc
1 #include <dcp/j2k.h>
2 #include <dcp/openjpeg_image.h>
3 #include <dcp/colour_conversion.h>
4 #include <dcp/rgb_xyz.h>
5 #include <Magick++.h>
6 #include <boost/thread.hpp>
7 #include <boost/foreach.hpp>
8 #include <list>
9 #include <iostream>
10
11 using std::list;
12 using std::cout;
13 using std::cerr;
14 using boost::shared_ptr;
15 using boost::optional;
16
17 #define WRITE_FIRST 1
18
19 void
20 thread (int iterations, shared_ptr<const dcp::OpenJPEGImage> image)
21 {
22 #ifdef WRITE_FIRST
23         static bool written = false;
24 #endif
25         for (int i = 0; i < iterations; ++i) {
26                 shared_ptr<const dcp::OpenJPEGImage> copy (new dcp::OpenJPEGImage (*image.get()));
27                 dcp::Data data = dcp::compress_j2k (copy, 100000000, 24, false, false);
28 #ifdef WRITE_FIRST
29                 if (!written) {
30                         FILE* f = fopen ("test.j2k", "wb");
31                         fwrite (data.data().get(), data.size(), 1, f);
32                         fclose (f);
33                         written = true;
34                 }
35 #endif
36         }
37 }
38
39 shared_ptr<const dcp::OpenJPEGImage>
40 load_frame (boost::filesystem::path file)
41 {
42         boost::uintmax_t const file_size = boost::filesystem::file_size (file);
43         FILE* f = dcp::fopen_boost (file, "rb");
44         if (!f) {
45                 cerr << "Could not open " << file.string() << "\n";
46                 exit (EXIT_FAILURE);
47         }
48
49         uint8_t* data = new uint8_t[file_size];
50         if (fread (data, 1, file_size, f) != file_size) {
51                 delete[] data;
52                 cerr << "Could not read " << file.string() << "\n";
53                 exit (EXIT_FAILURE);
54         }
55
56         fclose (f);
57         Magick::Blob blob;
58         blob.update (data, file_size);
59         delete[] data;
60
61         Magick::Image* magick_image = new Magick::Image (blob);
62         dcp::Size size (magick_image->columns(), magick_image->rows());
63
64         int const stride = size.width * 6;
65         uint8_t* rgb = new uint8_t[size.height * stride];
66
67         uint8_t* p = rgb;
68         for (int i = 0; i < size.height; ++i) {
69                 using namespace MagickCore;
70                 magick_image->write (0, i, size.width, 1, "RGB", ShortPixel, p);
71                 p += stride;
72         }
73
74         delete magick_image;
75
76         shared_ptr<dcp::OpenJPEGImage> xyz = dcp::rgb_to_xyz (rgb, size, stride, dcp::ColourConversion::rec709_to_xyz(), optional<dcp::NoteHandler> ());
77         delete[] rgb;
78
79         return xyz;
80 }
81
82 int
83 main (int argc, char* argv[])
84 {
85         if (argc < 4) {
86                 cout << "Syntax: " << argv[0] << " <threads> <iterations> <frame file>\n";
87                 exit (EXIT_FAILURE);
88         }
89
90         int const num_threads = atoi (argv[1]);
91         int const num_iterations = atoi (argv[2]);
92         boost::filesystem::path frame_file = argv[3];
93         cout << num_threads << " threads, " << num_iterations << " iterations, frame file " << frame_file.string() << ".\n";
94
95         shared_ptr<const dcp::OpenJPEGImage> image = load_frame (frame_file);
96
97         struct timeval start;
98         gettimeofday (&start, 0);
99
100         list<boost::thread*> threads;
101         for (int i = 0; i < num_threads; ++i) {
102                 threads.push_back (new boost::thread (boost::bind (&thread, num_iterations, image)));
103         }
104
105         BOOST_FOREACH (boost::thread* i, threads) {
106                 i->join ();
107         }
108
109         struct timeval stop;
110         gettimeofday (&stop, 0);
111
112         double const seconds = ((stop.tv_sec + double(stop.tv_usec) / 1000000) - (start.tv_sec + double(start.tv_usec) / 1000000));
113
114         cout << seconds << "s: " << (num_iterations * num_threads / seconds) << " fps.\n";
115 }