Reorganization, replacing CPU debayering entirely
592
camera.glade
|
@ -1,592 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- Generated with glade 3.37.0 -->
|
|
||||||
<interface>
|
|
||||||
<requires lib="gtk+" version="3.20"/>
|
|
||||||
<object class="GtkAdjustment" id="control_adj">
|
|
||||||
<property name="upper">100</property>
|
|
||||||
<property name="step-increment">1</property>
|
|
||||||
<property name="page-increment">10</property>
|
|
||||||
</object>
|
|
||||||
<object class="GtkWindow" id="window">
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="title" translatable="yes">Camera</property>
|
|
||||||
<property name="default-width">360</property>
|
|
||||||
<property name="default-height">640</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkStack" id="main_stack">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox" id="page_main">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkGLArea" id="preview">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<style>
|
|
||||||
<class name="black"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox" id="control_box">
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">10</property>
|
|
||||||
<property name="margin-end">10</property>
|
|
||||||
<property name="margin-top">10</property>
|
|
||||||
<property name="margin-bottom">10</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="control_name">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-end">10</property>
|
|
||||||
<property name="label" translatable="yes">ISO</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkScale" id="control_slider">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="adjustment">control_adj</property>
|
|
||||||
<property name="round-digits">1</property>
|
|
||||||
<property name="draw-value">False</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkToggleButton" id="control_auto">
|
|
||||||
<property name="label" translatable="yes">Auto</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<property name="margin-start">10</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="pack-type">end</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<style>
|
|
||||||
<class name="controlbox"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox" id="controls_box">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<child type="center">
|
|
||||||
<object class="GtkButton" id="shutter">
|
|
||||||
<property name="width-request">48</property>
|
|
||||||
<property name="height-request">48</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<property name="always-show-image">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="resource">/org/postmarketos/Megapixels/shutter-button.svg</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<style>
|
|
||||||
<class name="circular"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-top">8</property>
|
|
||||||
<property name="margin-bottom">8</property>
|
|
||||||
<property name="spacing">10</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="settings">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="resource">/org/postmarketos/Megapixels/settings-symbolic.svg</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="switch_camera">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="resource">/org/postmarketos/Megapixels/switch-camera.svg</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="padding">10</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-top">8</property>
|
|
||||||
<property name="margin-bottom">8</property>
|
|
||||||
<property name="spacing">10</property>
|
|
||||||
<child>
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="open_directory">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="resource">/org/postmarketos/Megapixels/folder-symbolic.svg</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="pack-type">end</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="open_last">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkStack" id="open_last_stack">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="thumb_last">
|
|
||||||
<property name="width-request">24</property>
|
|
||||||
<property name="height-request">24</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkSpinner" id="process_spinner">
|
|
||||||
<property name="width-request">24</property>
|
|
||||||
<property name="height-request">24</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="pack-type">end</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="padding">10</property>
|
|
||||||
<property name="pack-type">end</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="padding">10</property>
|
|
||||||
<property name="pack-type">end</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox" id="error_box">
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">10</property>
|
|
||||||
<property name="margin-end">10</property>
|
|
||||||
<property name="margin-top">10</property>
|
|
||||||
<property name="margin-bottom">10</property>
|
|
||||||
<property name="spacing">10</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="error_message">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="halign">start</property>
|
|
||||||
<property name="label" translatable="yes">No error</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="error_close">
|
|
||||||
<property name="label">gtk-close</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<property name="use-stock">True</property>
|
|
||||||
<property name="always-show-image">True</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<style>
|
|
||||||
<class name="errorbox"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="name">main</property>
|
|
||||||
<property name="title" translatable="yes">page0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkScrolledWindow" id="page_settings">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkViewport">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="shadow-type">none</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">10</property>
|
|
||||||
<property name="margin-end">10</property>
|
|
||||||
<property name="margin-top">10</property>
|
|
||||||
<property name="margin-bottom">10</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">10</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="settings_back">
|
|
||||||
<property name="label" translatable="yes">Back</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<property name="margin-start">10</property>
|
|
||||||
<property name="margin-end">10</property>
|
|
||||||
<style>
|
|
||||||
<class name="suggested-action"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label" translatable="yes">Settings aren't functional yet</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">4</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="halign">start</property>
|
|
||||||
<property name="label" translatable="yes">Photos</property>
|
|
||||||
<style>
|
|
||||||
<class name="heading"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="left-padding">12</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">6</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="halign">start</property>
|
|
||||||
<property name="label" translatable="yes">Resolution</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="halign">start</property>
|
|
||||||
<property name="label" translatable="yes">Storage mode</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">4</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRadioButton" id="store_vng">
|
|
||||||
<property name="label" translatable="yes">Debayer with VNG (slowest)</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">False</property>
|
|
||||||
<property name="active">True</property>
|
|
||||||
<property name="draw-indicator">True</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRadioButton" id="store_simple">
|
|
||||||
<property name="label" translatable="yes">Debayer with linear interpolation</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">False</property>
|
|
||||||
<property name="draw-indicator">True</property>
|
|
||||||
<property name="group">store_vng</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRadioButton" id="store_raw">
|
|
||||||
<property name="label" translatable="yes">Raw</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">False</property>
|
|
||||||
<property name="draw-indicator">True</property>
|
|
||||||
<property name="group">store_vng</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">5</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label_item">
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
<style>
|
|
||||||
<class name="view"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="name">settings</property>
|
|
||||||
<property name="title" translatable="yes">page1</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</interface>
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
#ifdef GL_ES
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
#ifdef GL_ES
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
attribute vec2 vert;
|
attribute vec2 vert;
|
||||||
attribute vec2 tex_coord;
|
attribute vec2 tex_coord;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
<object class="GtkGLArea" id="preview">
|
<object class="GtkGLArea" id="preview">
|
||||||
<property name="vexpand">1</property>
|
<property name="vexpand">1</property>
|
||||||
<property name="can-focus">0</property>
|
<property name="can-focus">0</property>
|
||||||
|
<property name="use-es">1</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
|
@ -1,37 +1,28 @@
|
||||||
precision highp float;
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
uniform sampler2D pixel_layout;
|
|
||||||
uniform mat3 color_matrix;
|
uniform mat3 color_matrix;
|
||||||
|
|
||||||
uniform vec2 pixel_size;
|
|
||||||
|
|
||||||
// varying vec2 uv1;
|
|
||||||
// varying vec2 uv2;
|
|
||||||
varying vec2 top_left_uv;
|
varying vec2 top_left_uv;
|
||||||
varying vec2 top_right_uv;
|
varying vec2 top_right_uv;
|
||||||
varying vec2 bottom_left_uv;
|
varying vec2 bottom_left_uv;
|
||||||
varying vec2 bottom_right_uv;
|
varying vec2 bottom_right_uv;
|
||||||
varying vec2 half_pixel_coord;
|
|
||||||
|
|
||||||
#define fetch(p) texture2D(texture, p).r
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 pixels = vec4(
|
// Note the coordinates for texture samples need to be a varying, as the
|
||||||
fetch(top_left_uv),
|
// Mali-400 has this as a fast path allowing 32-bit floats. Otherwise
|
||||||
fetch(top_right_uv),
|
// they end up as 16-bit floats and that's not accurate enough.
|
||||||
fetch(bottom_right_uv),
|
vec4 samples = vec4(
|
||||||
fetch(bottom_left_uv));
|
texture2D(texture, top_left_uv).r,
|
||||||
|
texture2D(texture, top_right_uv).r,
|
||||||
|
texture2D(texture, bottom_left_uv).r,
|
||||||
|
texture2D(texture, bottom_right_uv).r);
|
||||||
|
|
||||||
vec2 arrangement = floor(half_pixel_coord);
|
// Assume BGGR for now. Currently this just takes 3 of the four samples
|
||||||
|
// for each pixel, there's room here to do some better debayering.
|
||||||
vec2 is_bottom_left = step(1.0, arrangement);
|
vec3 color = samples.wyx;
|
||||||
|
|
||||||
// vec3 color = mix(
|
|
||||||
// mix(pixels.xyz, pixels.yzw, is_bottom_left.y),
|
|
||||||
// mix(pixels.wzy, pixels.zyx, is_bottom_left.y),
|
|
||||||
// is_bottom_left.x);
|
|
||||||
vec3 color = pixels.zyx;
|
|
||||||
|
|
||||||
// Fast SRGB estimate. See https://mimosa-pudica.net/fast-gamma/
|
// Fast SRGB estimate. See https://mimosa-pudica.net/fast-gamma/
|
||||||
vec3 srgb_color = (vec3(1.138) * inversesqrt(color) - vec3(0.138)) * color;
|
vec3 srgb_color = (vec3(1.138) * inversesqrt(color) - vec3(0.138)) * color;
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
precision highp float;
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
|
||||||
attribute vec2 vert;
|
attribute vec2 vert;
|
||||||
attribute vec2 tex_coord;
|
attribute vec2 tex_coord;
|
||||||
|
|
||||||
uniform mat3 transform;
|
uniform mat3 transform;
|
||||||
uniform vec2 pixel_size;
|
uniform vec2 pixel_size;
|
||||||
uniform vec2 half_image_size;
|
|
||||||
|
|
||||||
// varying vec2 uv1;
|
|
||||||
// varying vec2 uv2;
|
|
||||||
|
|
||||||
varying vec2 top_left_uv;
|
varying vec2 top_left_uv;
|
||||||
varying vec2 top_right_uv;
|
varying vec2 top_right_uv;
|
||||||
varying vec2 bottom_left_uv;
|
varying vec2 bottom_left_uv;
|
||||||
varying vec2 bottom_right_uv;
|
varying vec2 bottom_right_uv;
|
||||||
varying vec2 half_pixel_coord;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
top_left_uv = tex_coord - pixel_size / 2.0;
|
top_left_uv = tex_coord - pixel_size / 2.0;
|
||||||
|
@ -22,11 +19,5 @@ void main() {
|
||||||
top_right_uv = vec2(top_left_uv.x, bottom_right_uv.y);
|
top_right_uv = vec2(top_left_uv.x, bottom_right_uv.y);
|
||||||
bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y);
|
bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y);
|
||||||
|
|
||||||
// uv1 = tex_coord - pixel_size / 2.0;
|
|
||||||
// uv2 = tex_coord + pixel_size / 2.0;
|
|
||||||
// uv1 += pixel_size;
|
|
||||||
// uv2 += pixel_size;
|
|
||||||
half_pixel_coord = top_left_uv * half_image_size;
|
|
||||||
|
|
||||||
gl_Position = vec4(transform * vec3(vert, 1), 1);
|
gl_Position = vec4(transform * vec3(vert, 1), 1);
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,15 @@
|
||||||
|
resources = gnome.compile_resources('megapixels-resources',
|
||||||
|
'org.postmarketos.Megapixels.gresource.xml')
|
||||||
|
|
||||||
|
install_data(['org.postmarketos.Megapixels.desktop'],
|
||||||
|
install_dir: get_option('datadir') / 'applications')
|
||||||
|
|
||||||
|
install_data(['org.postmarketos.Megapixels.metainfo.xml'],
|
||||||
|
install_dir: get_option('datadir') / 'metainfo')
|
||||||
|
|
||||||
|
install_data('org.postmarketos.Megapixels.svg',
|
||||||
|
install_dir: join_paths(get_option('datadir'), 'icons/hicolor/scalable/apps'))
|
||||||
|
|
||||||
|
install_data(['postprocess.sh'],
|
||||||
|
install_dir: get_option('datadir') / 'megapixels/',
|
||||||
|
install_mode: 'rwxr-xr-x')
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/org/postmarketos/Megapixels">
|
||||||
|
<file preprocess="xml-stripblanks">camera.ui</file>
|
||||||
|
<file>camera.css</file>
|
||||||
|
<file preprocess="xml-stripblanks">switch-camera.svg</file>
|
||||||
|
<file preprocess="xml-stripblanks">shutter-button.svg</file>
|
||||||
|
<file preprocess="xml-stripblanks">folder-symbolic.svg</file>
|
||||||
|
<file preprocess="xml-stripblanks">settings-symbolic.svg</file>
|
||||||
|
<file>blit.vert</file>
|
||||||
|
<file>blit.frag</file>
|
||||||
|
<file>debayer.vert</file>
|
||||||
|
<file>debayer.frag</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -1,207 +0,0 @@
|
||||||
#include "camera.h"
|
|
||||||
#include "gl_quickpreview.h"
|
|
||||||
#include "gl_utils.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define VERTEX_ATTRIBUTE 0
|
|
||||||
#define TEX_COORD_ATTRIBUTE 1
|
|
||||||
|
|
||||||
struct _GLQuickPreview {
|
|
||||||
GLuint frame_buffer;
|
|
||||||
GLuint program;
|
|
||||||
GLuint uniform_transform;
|
|
||||||
GLuint uniform_pixel_size;
|
|
||||||
GLuint uniform_half_image_size;
|
|
||||||
GLuint uniform_texture;
|
|
||||||
GLuint uniform_pixel_layout;
|
|
||||||
GLuint uniform_srgb_map;
|
|
||||||
GLuint uniform_color_matrix;
|
|
||||||
|
|
||||||
GLuint pixel_layout_texture_id;
|
|
||||||
uint32_t pixel_layout_texture_width;
|
|
||||||
uint32_t pixel_layout_texture_height;
|
|
||||||
MPPixelFormat pixel_layout_texture_format;
|
|
||||||
};
|
|
||||||
|
|
||||||
GLQuickPreview *gl_quick_preview_new()
|
|
||||||
{
|
|
||||||
GLuint frame_buffer;
|
|
||||||
glGenFramebuffers(1, &frame_buffer);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
GLuint shaders[] = {
|
|
||||||
gl_load_shader("data/debayer.vert", GL_VERTEX_SHADER),
|
|
||||||
gl_load_shader("data/debayer.frag", GL_FRAGMENT_SHADER),
|
|
||||||
};
|
|
||||||
|
|
||||||
GLuint program = gl_link_program(shaders, 2);
|
|
||||||
glBindAttribLocation(program, VERTEX_ATTRIBUTE, "vert");
|
|
||||||
glBindAttribLocation(program, TEX_COORD_ATTRIBUTE, "tex_coord");
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
GLuint pixel_layout_texture_id;
|
|
||||||
glGenTextures(1, &pixel_layout_texture_id);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
GLQuickPreview *self = malloc(sizeof(GLQuickPreview));
|
|
||||||
self->frame_buffer = frame_buffer;
|
|
||||||
self->program = program;
|
|
||||||
|
|
||||||
self->uniform_transform = glGetUniformLocation(self->program, "transform");
|
|
||||||
self->uniform_pixel_size = glGetUniformLocation(self->program, "pixel_size");
|
|
||||||
self->uniform_half_image_size = glGetUniformLocation(self->program, "half_image_size");
|
|
||||||
self->uniform_texture = glGetUniformLocation(self->program, "texture");
|
|
||||||
self->uniform_pixel_layout = glGetUniformLocation(self->program, "pixel_layout");
|
|
||||||
self->uniform_color_matrix = glGetUniformLocation(self->program, "color_matrix");
|
|
||||||
self->uniform_srgb_map = glGetUniformLocation(self->program, "srgb_map");
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
self->pixel_layout_texture_id = pixel_layout_texture_id;
|
|
||||||
self->pixel_layout_texture_width = 0;
|
|
||||||
self->pixel_layout_texture_height = 0;
|
|
||||||
self->pixel_layout_texture_format = MP_PIXEL_FMT_BGGR8;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gl_quick_preview_free(GLQuickPreview *self)
|
|
||||||
{
|
|
||||||
glDeleteFramebuffers(1, &self->frame_buffer);
|
|
||||||
|
|
||||||
free(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ql_quick_preview_supports_format(GLQuickPreview *self, const MPPixelFormat format)
|
|
||||||
{
|
|
||||||
return format == MP_PIXEL_FMT_BGGR8;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
gl_quick_preview(GLQuickPreview *self,
|
|
||||||
GLuint dst_id,
|
|
||||||
const uint32_t dst_width, const uint32_t dst_height,
|
|
||||||
GLuint source_id,
|
|
||||||
const uint32_t src_width, const uint32_t src_height,
|
|
||||||
const MPPixelFormat format,
|
|
||||||
const uint32_t rotation,
|
|
||||||
const bool mirrored,
|
|
||||||
const float *colormatrix,
|
|
||||||
const uint8_t blacklevel)
|
|
||||||
{
|
|
||||||
// Generate pixel layout image
|
|
||||||
if (src_width != self->pixel_layout_texture_width
|
|
||||||
|| src_height != self->pixel_layout_texture_height
|
|
||||||
|| format != self->pixel_layout_texture_format) {
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, self->pixel_layout_texture_id);
|
|
||||||
|
|
||||||
uint16_t *buffer = malloc(src_width * src_height * sizeof(uint16_t));
|
|
||||||
for (size_t y = 0; y < src_height; ++y) {
|
|
||||||
for (size_t x = 0; x < src_width; ++x) {
|
|
||||||
buffer[x + y * src_width] =
|
|
||||||
(y % 2) == 0
|
|
||||||
? ((x % 2) == 0 ? 0b1111 << 4 : 0b1111 << 8)
|
|
||||||
: ((x % 2) == 0 ? 0b1111 << 8 : 0b1111 << 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_width, src_height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, buffer);
|
|
||||||
check_gl();
|
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
self->pixel_layout_texture_width = src_width;
|
|
||||||
self->pixel_layout_texture_height = src_height;
|
|
||||||
self->pixel_layout_texture_format = format;
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
check_gl();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(ql_quick_preview_supports_format(self, format));
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self->frame_buffer);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, dst_id);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_id, 0);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
glViewport(0, 0, dst_width, dst_height);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
|
||||||
|
|
||||||
glUseProgram(self->program);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
GLfloat rotation_list[4] = { 0, -1, 0, 1 };
|
|
||||||
int rotation_index = 4 - rotation / 90;
|
|
||||||
|
|
||||||
GLfloat sin_rot = rotation_list[rotation_index];
|
|
||||||
GLfloat cos_rot = rotation_list[(rotation_index + 1) % 4];
|
|
||||||
GLfloat scale_x = mirrored ? 1 : -1;
|
|
||||||
GLfloat matrix[9] = {
|
|
||||||
cos_rot * scale_x, sin_rot, 0,
|
|
||||||
-sin_rot * scale_x, cos_rot, 0,
|
|
||||||
0, 0, 1,
|
|
||||||
};
|
|
||||||
glUniformMatrix3fv(self->uniform_transform, 1, GL_FALSE, matrix);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
glUniform2f(self->uniform_half_image_size, src_width / 2, src_height / 2);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
GLfloat pixel_size_x = 1.0f / src_width;
|
|
||||||
GLfloat pixel_size_y = 1.0f / src_height;
|
|
||||||
glUniform2f(self->uniform_pixel_size, pixel_size_x, pixel_size_y);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, source_id);
|
|
||||||
glUniform1i(self->uniform_texture, 0);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, self->pixel_layout_texture_id);
|
|
||||||
glUniform1i(self->uniform_pixel_layout, 1);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
if (colormatrix)
|
|
||||||
{
|
|
||||||
GLfloat transposed[9];
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
for (int j = 0; j < 3; ++j)
|
|
||||||
transposed[i + j * 3] = colormatrix[j + i * 3];
|
|
||||||
|
|
||||||
glUniformMatrix3fv(self->uniform_color_matrix, 1, GL_FALSE, transposed);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static const GLfloat identity[9] = {
|
|
||||||
1, 0, 0,
|
|
||||||
0, 1, 0,
|
|
||||||
0, 0, 1,
|
|
||||||
};
|
|
||||||
glUniformMatrix3fv(self->uniform_color_matrix, 1, GL_FALSE, identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
glVertexAttribPointer(VERTEX_ATTRIBUTE, 2, GL_FLOAT, 0, 0, gl_quad_vertices);
|
|
||||||
glEnableVertexAttribArray(VERTEX_ATTRIBUTE);
|
|
||||||
glVertexAttribPointer(TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, 0, 0, gl_quad_texcoords);
|
|
||||||
glEnableVertexAttribArray(TEX_COORD_ATTRIBUTE);
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
// TODO: Render
|
|
||||||
// glClearColor(0, 0, 1, 0);
|
|
||||||
// glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
// glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
// glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
#include "quickpreview.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <GLES2/gl2.h>
|
|
||||||
|
|
||||||
typedef struct _GLQuickPreview GLQuickPreview;
|
|
||||||
|
|
||||||
GLQuickPreview* gl_quick_preview_new();
|
|
||||||
void gl_quick_preview_free(GLQuickPreview *self);
|
|
||||||
|
|
||||||
bool ql_quick_preview_supports_format(GLQuickPreview *self, const MPPixelFormat format);
|
|
||||||
bool gl_quick_preview(GLQuickPreview *self,
|
|
||||||
GLuint dst_id,
|
|
||||||
const uint32_t dst_width, const uint32_t dst_height,
|
|
||||||
GLuint source_id,
|
|
||||||
const uint32_t src_width, const uint32_t src_height,
|
|
||||||
const MPPixelFormat format,
|
|
||||||
const uint32_t rotation,
|
|
||||||
const bool mirrored,
|
|
||||||
const float *colormatrix,
|
|
||||||
const uint8_t blacklevel);
|
|
128
gl_utils.c
|
@ -1,128 +0,0 @@
|
||||||
#include "gl_utils.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
void __check_gl(const char *file, int line)
|
|
||||||
{
|
|
||||||
GLenum error = glGetError();
|
|
||||||
|
|
||||||
const char *name;
|
|
||||||
switch (error) {
|
|
||||||
case GL_NO_ERROR:
|
|
||||||
return; // no error
|
|
||||||
case GL_INVALID_ENUM:
|
|
||||||
name = "GL_INVALID_ENUM";
|
|
||||||
break;
|
|
||||||
case GL_INVALID_VALUE:
|
|
||||||
name = "GL_INVALID_VALUE";
|
|
||||||
break;
|
|
||||||
case GL_INVALID_OPERATION:
|
|
||||||
name = "GL_INVALID_OPERATION";
|
|
||||||
break;
|
|
||||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
|
||||||
name = "GL_INVALID_FRAMEBUFFER_OPERATION";
|
|
||||||
break;
|
|
||||||
case GL_OUT_OF_MEMORY:
|
|
||||||
name = "GL_OUT_OF_MEMORY";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = "UNKNOWN ERROR!";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("GL error at %s:%d - %s\n", file, line, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GLfloat gl_quad_vertices[] = {
|
|
||||||
-1, -1,
|
|
||||||
1, -1,
|
|
||||||
-1, 1,
|
|
||||||
1, 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const GLfloat gl_quad_texcoords[] = {
|
|
||||||
0, 0,
|
|
||||||
1, 0,
|
|
||||||
0, 1,
|
|
||||||
1, 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
GLuint
|
|
||||||
gl_load_shader(const char *path, GLenum type)
|
|
||||||
{
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
FILE *f = fopen(path, "r");
|
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
GLint size = ftell(f);
|
|
||||||
char *source = malloc(sizeof(char) * size);
|
|
||||||
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
if (fread(source, size, 1, f) == 0) {
|
|
||||||
printf("Failed to read shader file\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint shader = glCreateShader(type);
|
|
||||||
assert(shader != 0);
|
|
||||||
glShaderSource(shader, 1, (const GLchar * const*)&source, &size);
|
|
||||||
glCompileShader(shader);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
// Check compile status
|
|
||||||
GLint success;
|
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
|
||||||
if (success == GL_FALSE) {
|
|
||||||
printf("Shader compilation failed for %s\n", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint log_length;
|
|
||||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
|
||||||
if (log_length > 0) {
|
|
||||||
char *log = malloc(sizeof(char) * log_length);
|
|
||||||
glGetShaderInfoLog(shader, log_length - 1, &log_length, log);
|
|
||||||
|
|
||||||
printf("Shader %s log: %s\n", path, log);
|
|
||||||
free(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(source);
|
|
||||||
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint
|
|
||||||
gl_link_program(GLuint *shaders, size_t num_shaders)
|
|
||||||
{
|
|
||||||
GLuint program = glCreateProgram();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < num_shaders; ++i) {
|
|
||||||
glAttachShader(program, shaders[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
glLinkProgram(program);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
GLint success;
|
|
||||||
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
|
||||||
if (success == GL_FALSE) {
|
|
||||||
printf("Program linking failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint log_length;
|
|
||||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
|
|
||||||
if (log_length > 0) {
|
|
||||||
char *log = malloc(sizeof(char) * log_length);
|
|
||||||
glGetProgramInfoLog(program, log_length - 1, &log_length, log);
|
|
||||||
|
|
||||||
printf("Program log: %s\n", log);
|
|
||||||
free(log);
|
|
||||||
}
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
return program;
|
|
||||||
}
|
|
13
gl_utils.h
|
@ -1,13 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <GLES2/gl2.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#define check_gl() __check_gl(__FILE__, __LINE__)
|
|
||||||
void __check_gl(const char *file, int line);
|
|
||||||
|
|
||||||
extern const GLfloat gl_quad_vertices[8];
|
|
||||||
extern const GLfloat gl_quad_texcoords[8];
|
|
||||||
|
|
||||||
GLuint gl_load_shader(const char *path, GLenum type);
|
|
||||||
GLuint gl_link_program(GLuint *shaders, size_t num_shaders);
|
|
80
meson.build
|
@ -1,78 +1,76 @@
|
||||||
project('megapixels', 'c')
|
project('megapixels', 'c')
|
||||||
|
|
||||||
gnome = import('gnome')
|
gnome = import('gnome')
|
||||||
gtkdep = dependency('gtk4')
|
gtkdep = dependency('gtk4')
|
||||||
tiff = dependency('libtiff-4')
|
tiff = dependency('libtiff-4')
|
||||||
zbar = dependency('zbar')
|
zbar = dependency('zbar')
|
||||||
threads = dependency('threads')
|
threads = dependency('threads')
|
||||||
gl = dependency('gl')
|
# gl = dependency('gl')
|
||||||
egl = dependency('egl')
|
epoxy = dependency('epoxy')
|
||||||
|
|
||||||
cc = meson.get_compiler('c')
|
cc = meson.get_compiler('c')
|
||||||
libm = cc.find_library('m', required: false)
|
libm = cc.find_library('m', required: false)
|
||||||
|
|
||||||
resources = gnome.compile_resources('megapixels-resources', 'org.postmarketos.Megapixels.gresource.xml')
|
subdir('data')
|
||||||
|
|
||||||
conf = configuration_data()
|
conf = configuration_data()
|
||||||
conf.set_quoted('DATADIR', join_paths(get_option('prefix'), get_option('datadir')))
|
conf.set_quoted('DATADIR', join_paths(get_option('prefix'), get_option('datadir')))
|
||||||
conf.set_quoted('SYSCONFDIR', get_option('sysconfdir'))
|
conf.set_quoted('SYSCONFDIR', get_option('sysconfdir'))
|
||||||
configure_file(
|
configure_file(
|
||||||
output: 'config.h',
|
output: 'config.h',
|
||||||
configuration: conf )
|
configuration: conf)
|
||||||
|
|
||||||
# Define DEBUG for debug builds only (debugoptimized is not included on this one)
|
# Define DEBUG for debug builds only (debugoptimized is not included on this one)
|
||||||
if get_option('buildtype') == 'debug'
|
if get_option('buildtype') == 'debug'
|
||||||
add_global_arguments('-DDEBUG', language: 'c')
|
add_global_arguments('-DDEBUG', language: 'c')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Workaround for libtiff having ABI changes but not changing the internal version number
|
# Workaround for libtiff having ABI changes but not changing the internal
|
||||||
|
# version number
|
||||||
if get_option('tiffcfapattern')
|
if get_option('tiffcfapattern')
|
||||||
add_global_arguments('-DLIBTIFF_CFA_PATTERN', language: 'c')
|
add_global_arguments('-DLIBTIFF_CFA_PATTERN', language: 'c')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
executable('megapixels',
|
executable('megapixels',
|
||||||
'main.c',
|
'src/main.c',
|
||||||
'ini.c',
|
'src/ini.c',
|
||||||
'quickpreview.c',
|
'src/gles2_debayer.c',
|
||||||
'gl_quickpreview.c',
|
'src/gl_util.c',
|
||||||
'gl_utils.c',
|
'src/camera.c',
|
||||||
'camera.c',
|
'src/device.c',
|
||||||
'device.c',
|
'src/pipeline.c',
|
||||||
'pipeline.c',
|
'src/camera_config.c',
|
||||||
'camera_config.c',
|
'src/io_pipeline.c',
|
||||||
'io_pipeline.c',
|
'src/process_pipeline.c',
|
||||||
'process_pipeline.c',
|
'src/zbar_pipeline.c',
|
||||||
'zbar_pipeline.c',
|
'src/matrix.c',
|
||||||
'matrix.c',
|
|
||||||
resources,
|
resources,
|
||||||
dependencies : [gtkdep, libm, tiff, zbar, threads, gl, egl],
|
include_directories: 'src/',
|
||||||
install : true,
|
dependencies: [gtkdep, libm, tiff, zbar, threads, epoxy],
|
||||||
link_args : '-Wl,-ldl')
|
install: true,
|
||||||
|
link_args: '-Wl,-ldl')
|
||||||
|
|
||||||
install_data(['data/org.postmarketos.Megapixels.desktop'],
|
install_data(
|
||||||
install_dir : get_option('datadir') / 'applications')
|
[
|
||||||
|
|
||||||
install_data(['data/org.postmarketos.Megapixels.metainfo.xml'],
|
|
||||||
install_dir : get_option('datadir') / 'metainfo')
|
|
||||||
|
|
||||||
install_data('data/org.postmarketos.Megapixels.svg',
|
|
||||||
install_dir: join_paths(get_option('datadir'), 'icons/hicolor/scalable/apps')
|
|
||||||
)
|
|
||||||
|
|
||||||
install_data([
|
|
||||||
'config/pine64,pinephone-1.0.ini',
|
'config/pine64,pinephone-1.0.ini',
|
||||||
'config/pine64,pinephone-1.1.ini',
|
'config/pine64,pinephone-1.1.ini',
|
||||||
'config/pine64,pinephone-1.2.ini',
|
'config/pine64,pinephone-1.2.ini',
|
||||||
'config/pine64,pinetab.ini',
|
'config/pine64,pinetab.ini',
|
||||||
],
|
],
|
||||||
install_dir : get_option('datadir') / 'megapixels/config/')
|
install_dir: get_option('datadir') / 'megapixels/config/')
|
||||||
|
|
||||||
install_data(['postprocess.sh'],
|
|
||||||
install_dir : get_option('datadir') / 'megapixels/',
|
|
||||||
install_mode: 'rwxr-xr-x')
|
|
||||||
|
|
||||||
# Tools
|
# Tools
|
||||||
executable('megapixels-list-devices', 'tools/list_devices.c', 'device.c', dependencies: [gtkdep], install: true)
|
executable('megapixels-list-devices',
|
||||||
executable('megapixels-camera-test', 'tools/camera_test.c', 'camera.c', 'device.c', dependencies: [gtkdep], install: true)
|
'tools/list_devices.c',
|
||||||
|
'src/device.c',
|
||||||
|
include_directories: 'src/',
|
||||||
|
dependencies: [gtkdep],
|
||||||
|
install: true)
|
||||||
|
|
||||||
test_quickpreview = executable('test_quickpreview', 'tests/test_quickpreview.c', 'quickpreview.c', 'camera.c', dependencies: [gtkdep])
|
executable('megapixels-camera-test',
|
||||||
test('quickpreview', test_quickpreview)
|
'tools/camera_test.c',
|
||||||
|
'src/camera.c',
|
||||||
|
'src/device.c',
|
||||||
|
include_directories: 'src/',
|
||||||
|
dependencies: [gtkdep],
|
||||||
|
install: true)
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<gresources>
|
|
||||||
<gresource prefix="/org/postmarketos/Megapixels">
|
|
||||||
<file>camera.glade</file>
|
|
||||||
<file>camera.css</file>
|
|
||||||
<file>switch-camera.svg</file>
|
|
||||||
<file>shutter-button.svg</file>
|
|
||||||
<file>folder-symbolic.svg</file>
|
|
||||||
<file>settings-symbolic.svg</file>
|
|
||||||
</gresource>
|
|
||||||
</gresources>
|
|
351
quickpreview.c
|
@ -1,351 +0,0 @@
|
||||||
/*
|
|
||||||
* Fast but bad debayer method that scales and rotates by skipping source
|
|
||||||
* pixels and doesn't interpolate any values at all
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "quickpreview.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/* Linear -> sRGB lookup table */
|
|
||||||
static const uint8_t srgb[] = {
|
|
||||||
0, 12, 21, 28, 33, 38, 42, 46, 49, 52, 55, 58, 61, 63, 66, 68, 70,
|
|
||||||
73, 75, 77, 79, 81, 82, 84, 86, 88, 89, 91, 93, 94, 96, 97, 99, 100,
|
|
||||||
102, 103, 104, 106, 107, 109, 110, 111, 112, 114, 115, 116, 117, 118,
|
|
||||||
120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134,
|
|
||||||
135, 136, 137, 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147,
|
|
||||||
148, 149, 150, 151, 151, 152, 153, 154, 155, 156, 157, 157, 158, 159,
|
|
||||||
160, 161, 161, 162, 163, 164, 165, 165, 166, 167, 168, 168, 169, 170,
|
|
||||||
171, 171, 172, 173, 174, 174, 175, 176, 176, 177, 178, 179, 179, 180,
|
|
||||||
181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189,
|
|
||||||
190, 191, 191, 192, 193, 193, 194, 194, 195, 196, 196, 197, 197, 198,
|
|
||||||
199, 199, 200, 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206,
|
|
||||||
207, 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214,
|
|
||||||
215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222,
|
|
||||||
222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228, 228, 229, 229,
|
|
||||||
230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236,
|
|
||||||
237, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243,
|
|
||||||
243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249,
|
|
||||||
250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline uint32_t
|
|
||||||
pack_rgb(uint8_t r, uint8_t g, uint8_t b)
|
|
||||||
{
|
|
||||||
return (r << 16) | (g << 8) | b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t
|
|
||||||
convert_yuv_to_srgb(uint8_t y, uint8_t u, uint8_t v)
|
|
||||||
{
|
|
||||||
uint32_t r = 1.164f * y + 1.596f * (v - 128);
|
|
||||||
uint32_t g = 1.164f * y - 0.813f * (v - 128) - 0.391f * (u - 128);
|
|
||||||
uint32_t b = 1.164f * y + 2.018f * (u - 128);
|
|
||||||
return pack_rgb(r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t
|
|
||||||
apply_colormatrix(uint32_t color, const float *colormatrix)
|
|
||||||
{
|
|
||||||
if (!colormatrix) {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t r = (color >> 16) * colormatrix[0] +
|
|
||||||
((color >> 8) & 0xFF) * colormatrix[1] +
|
|
||||||
(color & 0xFF) * colormatrix[2];
|
|
||||||
uint32_t g = (color >> 16) * colormatrix[3] +
|
|
||||||
((color >> 8) & 0xFF) * colormatrix[4] +
|
|
||||||
(color & 0xFF) * colormatrix[5];
|
|
||||||
uint32_t b = (color >> 16) * colormatrix[6] +
|
|
||||||
((color >> 8) & 0xFF) * colormatrix[7] +
|
|
||||||
(color & 0xFF) * colormatrix[8];
|
|
||||||
|
|
||||||
// Clip colors
|
|
||||||
if (r > 0xFF)
|
|
||||||
r = 0xFF;
|
|
||||||
if (g > 0xFF)
|
|
||||||
g = 0xFF;
|
|
||||||
if (b > 0xFF)
|
|
||||||
b = 0xFF;
|
|
||||||
return pack_rgb(r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t
|
|
||||||
coord_map(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int rotation,
|
|
||||||
bool mirrored)
|
|
||||||
{
|
|
||||||
uint32_t x_r, y_r;
|
|
||||||
if (rotation == 0) {
|
|
||||||
x_r = x;
|
|
||||||
y_r = y;
|
|
||||||
} else if (rotation == 90) {
|
|
||||||
x_r = y;
|
|
||||||
y_r = height - x - 1;
|
|
||||||
} else if (rotation == 270) {
|
|
||||||
x_r = width - y - 1;
|
|
||||||
y_r = x;
|
|
||||||
} else {
|
|
||||||
x_r = width - x - 1;
|
|
||||||
y_r = height - y - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mirrored) {
|
|
||||||
x_r = width - x_r - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t index = y_r * width + x_r;
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(index < width * height);
|
|
||||||
#endif
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
quick_preview_rggb8(uint32_t *dst, const uint32_t dst_width,
|
|
||||||
const uint32_t dst_height, const uint8_t *src,
|
|
||||||
const uint32_t src_width, const uint32_t src_height,
|
|
||||||
const MPPixelFormat format, const uint32_t rotation,
|
|
||||||
const bool mirrored, const float *colormatrix,
|
|
||||||
const uint8_t blacklevel, const uint32_t skip)
|
|
||||||
{
|
|
||||||
uint32_t src_y = 0, dst_y = 0;
|
|
||||||
while (src_y < src_height) {
|
|
||||||
uint32_t src_x = 0, dst_x = 0;
|
|
||||||
while (src_x < src_width) {
|
|
||||||
uint32_t src_i = src_y * src_width + src_x;
|
|
||||||
|
|
||||||
uint8_t b0 = srgb[src[src_i] - blacklevel];
|
|
||||||
uint8_t b1 = srgb[src[src_i + 1] - blacklevel];
|
|
||||||
uint8_t b2 = srgb[src[src_i + src_width + 1] - blacklevel];
|
|
||||||
|
|
||||||
uint32_t color;
|
|
||||||
switch (format) {
|
|
||||||
case MP_PIXEL_FMT_BGGR8:
|
|
||||||
color = pack_rgb(b2, b1, b0);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_GBRG8:
|
|
||||||
color = pack_rgb(b2, b0, b1);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_GRBG8:
|
|
||||||
color = pack_rgb(b1, b0, b2);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_RGGB8:
|
|
||||||
color = pack_rgb(b0, b1, b2);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
color = apply_colormatrix(color, colormatrix);
|
|
||||||
|
|
||||||
dst[coord_map(dst_x, dst_y, dst_width, dst_height, rotation,
|
|
||||||
mirrored)] = color;
|
|
||||||
|
|
||||||
src_x += 2 + 2 * skip;
|
|
||||||
++dst_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_y += 2 + 2 * skip;
|
|
||||||
++dst_y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
quick_preview_rggb10(uint32_t *dst, const uint32_t dst_width,
|
|
||||||
const uint32_t dst_height, const uint8_t *src,
|
|
||||||
const uint32_t src_width, const uint32_t src_height,
|
|
||||||
const MPPixelFormat format, const uint32_t rotation,
|
|
||||||
const bool mirrored, const float *colormatrix,
|
|
||||||
const uint8_t blacklevel, const uint32_t skip)
|
|
||||||
{
|
|
||||||
assert(src_width % 2 == 0);
|
|
||||||
|
|
||||||
uint32_t width_bytes = mp_pixel_format_width_to_bytes(format, src_width);
|
|
||||||
|
|
||||||
uint32_t src_y = 0, dst_y = 0;
|
|
||||||
while (src_y < src_height) {
|
|
||||||
uint32_t src_x = 0, dst_x = 0;
|
|
||||||
while (src_x < width_bytes) {
|
|
||||||
uint32_t src_i = src_y * width_bytes + src_x;
|
|
||||||
|
|
||||||
uint8_t b0 = srgb[src[src_i] - blacklevel];
|
|
||||||
uint8_t b1 = srgb[src[src_i + 1] - blacklevel];
|
|
||||||
uint8_t b2 = srgb[src[src_i + width_bytes + 1] - blacklevel];
|
|
||||||
|
|
||||||
uint32_t color;
|
|
||||||
switch (format) {
|
|
||||||
case MP_PIXEL_FMT_BGGR10P:
|
|
||||||
color = pack_rgb(b2, b1, b0);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_GBRG10P:
|
|
||||||
color = pack_rgb(b2, b0, b1);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_GRBG10P:
|
|
||||||
color = pack_rgb(b1, b0, b2);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_RGGB10P:
|
|
||||||
color = pack_rgb(b0, b1, b2);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
color = apply_colormatrix(color, colormatrix);
|
|
||||||
|
|
||||||
dst[coord_map(dst_x, dst_y, dst_width, dst_height, rotation,
|
|
||||||
mirrored)] = color;
|
|
||||||
|
|
||||||
uint32_t advance = 1 + skip;
|
|
||||||
if (src_x % 5 == 0) {
|
|
||||||
src_x += 2 * (advance % 2) + 5 * (advance / 2);
|
|
||||||
} else {
|
|
||||||
src_x += 3 * (advance % 2) + 5 * (advance / 2);
|
|
||||||
}
|
|
||||||
++dst_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_y += 2 + 2 * skip;
|
|
||||||
++dst_y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
quick_preview_yuv(uint32_t *dst, const uint32_t dst_width, const uint32_t dst_height,
|
|
||||||
const uint8_t *src, const uint32_t src_width,
|
|
||||||
const uint32_t src_height, const MPPixelFormat format,
|
|
||||||
const uint32_t rotation, const bool mirrored,
|
|
||||||
const float *colormatrix, const uint32_t skip)
|
|
||||||
{
|
|
||||||
assert(src_width % 2 == 0);
|
|
||||||
|
|
||||||
uint32_t width_bytes = src_width * 2;
|
|
||||||
|
|
||||||
uint32_t unrot_dst_width = dst_width;
|
|
||||||
if (rotation != 0 && rotation != 180) {
|
|
||||||
unrot_dst_width = dst_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t src_y = 0, dst_y = 0;
|
|
||||||
while (src_y < src_height) {
|
|
||||||
uint32_t src_x = 0, dst_x = 0;
|
|
||||||
while (src_x < width_bytes) {
|
|
||||||
uint32_t src_i = src_y * width_bytes + src_x;
|
|
||||||
|
|
||||||
uint8_t b0 = src[src_i];
|
|
||||||
uint8_t b1 = src[src_i + 1];
|
|
||||||
uint8_t b2 = src[src_i + 2];
|
|
||||||
uint8_t b3 = src[src_i + 3];
|
|
||||||
|
|
||||||
uint32_t color1, color2;
|
|
||||||
switch (format) {
|
|
||||||
case MP_PIXEL_FMT_UYVY:
|
|
||||||
color1 = convert_yuv_to_srgb(b1, b0, b2);
|
|
||||||
color2 = convert_yuv_to_srgb(b3, b0, b2);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_YUYV:
|
|
||||||
color1 = convert_yuv_to_srgb(b0, b1, b3);
|
|
||||||
color2 = convert_yuv_to_srgb(b2, b1, b3);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
color1 = apply_colormatrix(color1, colormatrix);
|
|
||||||
color2 = apply_colormatrix(color2, colormatrix);
|
|
||||||
|
|
||||||
uint32_t dst_i1 = coord_map(dst_x, dst_y, dst_width,
|
|
||||||
dst_height, rotation, mirrored);
|
|
||||||
dst[dst_i1] = color1;
|
|
||||||
++dst_x;
|
|
||||||
|
|
||||||
// The last pixel needs to be skipped if we have an odd un-rotated width
|
|
||||||
if (dst_x < unrot_dst_width) {
|
|
||||||
uint32_t dst_i2 =
|
|
||||||
coord_map(dst_x, dst_y, dst_width,
|
|
||||||
dst_height, rotation, mirrored);
|
|
||||||
dst[dst_i2] = color2;
|
|
||||||
++dst_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_x += 4 + 4 * skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_y += 1 + skip;
|
|
||||||
++dst_y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
quick_preview(uint32_t *dst, const uint32_t dst_width, const uint32_t dst_height,
|
|
||||||
const uint8_t *src, const uint32_t src_width,
|
|
||||||
const uint32_t src_height, const MPPixelFormat format,
|
|
||||||
const uint32_t rotation, const bool mirrored, const float *colormatrix,
|
|
||||||
const uint8_t blacklevel, const uint32_t skip)
|
|
||||||
{
|
|
||||||
switch (format) {
|
|
||||||
case MP_PIXEL_FMT_BGGR8:
|
|
||||||
case MP_PIXEL_FMT_GBRG8:
|
|
||||||
case MP_PIXEL_FMT_GRBG8:
|
|
||||||
case MP_PIXEL_FMT_RGGB8:
|
|
||||||
quick_preview_rggb8(dst, dst_width, dst_height, src, src_width,
|
|
||||||
src_height, format, rotation, mirrored,
|
|
||||||
colormatrix, blacklevel, skip);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_BGGR10P:
|
|
||||||
case MP_PIXEL_FMT_GBRG10P:
|
|
||||||
case MP_PIXEL_FMT_GRBG10P:
|
|
||||||
case MP_PIXEL_FMT_RGGB10P:
|
|
||||||
quick_preview_rggb10(dst, dst_width, dst_height, src, src_width,
|
|
||||||
src_height, format, rotation, mirrored,
|
|
||||||
colormatrix, blacklevel, skip);
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_UYVY:
|
|
||||||
case MP_PIXEL_FMT_YUYV:
|
|
||||||
quick_preview_yuv(dst, dst_width, dst_height, src, src_width,
|
|
||||||
src_height, format, rotation, mirrored,
|
|
||||||
colormatrix, skip);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t
|
|
||||||
div_ceil(uint32_t x, uint32_t y)
|
|
||||||
{
|
|
||||||
return x / y + !!(x % y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
quick_preview_size(uint32_t *dst_width, uint32_t *dst_height, uint32_t *skip,
|
|
||||||
const uint32_t preview_width, const uint32_t preview_height,
|
|
||||||
const uint32_t src_width, const uint32_t src_height,
|
|
||||||
const MPPixelFormat format, const int rotation)
|
|
||||||
{
|
|
||||||
uint32_t colors_x = mp_pixel_format_width_to_colors(format, src_width);
|
|
||||||
uint32_t colors_y = mp_pixel_format_height_to_colors(format, src_height);
|
|
||||||
|
|
||||||
if (rotation != 0 && rotation != 180) {
|
|
||||||
uint32_t tmp = colors_x;
|
|
||||||
colors_x = colors_y;
|
|
||||||
colors_y = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t scale_x = colors_x / preview_width;
|
|
||||||
uint32_t scale_y = colors_y / preview_height;
|
|
||||||
|
|
||||||
if (scale_x > 0)
|
|
||||||
--scale_x;
|
|
||||||
if (scale_y > 0)
|
|
||||||
--scale_y;
|
|
||||||
*skip = scale_x > scale_y ? scale_x : scale_y;
|
|
||||||
|
|
||||||
*dst_width = div_ceil(colors_x, (1 + *skip));
|
|
||||||
if (*dst_width <= 0)
|
|
||||||
*dst_width = 1;
|
|
||||||
|
|
||||||
*dst_height = div_ceil(colors_y, (1 + *skip));
|
|
||||||
if (*dst_height <= 0)
|
|
||||||
*dst_height = 1;
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#include "camera.h"
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
void quick_preview(uint32_t *dst, const uint32_t dst_width,
|
|
||||||
const uint32_t dst_height, const uint8_t *src,
|
|
||||||
const uint32_t src_width, const uint32_t src_height,
|
|
||||||
const MPPixelFormat format, const uint32_t rotation,
|
|
||||||
const bool mirrored, const float *colormatrix,
|
|
||||||
const uint8_t blacklevel, const uint32_t skip);
|
|
||||||
|
|
||||||
void quick_preview_size(uint32_t *dst_width, uint32_t *dst_height, uint32_t *skip,
|
|
||||||
const uint32_t preview_width, const uint32_t preview_height,
|
|
||||||
const uint32_t src_width, const uint32_t src_height,
|
|
||||||
const MPPixelFormat format, const int rotation);
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
#include "gl_util.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <gmodule.h>
|
||||||
|
#include <gdk/gdk.h>
|
||||||
|
|
||||||
|
void gl_util_check_error(const char *file, int line)
|
||||||
|
{
|
||||||
|
GLenum error = glGetError();
|
||||||
|
|
||||||
|
const char *name;
|
||||||
|
switch (error) {
|
||||||
|
case GL_NO_ERROR:
|
||||||
|
return; // no error
|
||||||
|
case GL_INVALID_ENUM:
|
||||||
|
name = "GL_INVALID_ENUM";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_VALUE:
|
||||||
|
name = "GL_INVALID_VALUE";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_OPERATION:
|
||||||
|
name = "GL_INVALID_OPERATION";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||||
|
name = "GL_INVALID_FRAMEBUFFER_OPERATION";
|
||||||
|
break;
|
||||||
|
case GL_OUT_OF_MEMORY:
|
||||||
|
name = "GL_OUT_OF_MEMORY";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
name = "UNKNOWN ERROR!";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("GL error at %s:%d - %s\n", file, line, name);
|
||||||
|
|
||||||
|
// raise(SIGTRAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint
|
||||||
|
gl_util_load_shader(const char *resource, GLenum type, const char **extra_sources, size_t num_extra)
|
||||||
|
{
|
||||||
|
GdkGLContext *context = gdk_gl_context_get_current();
|
||||||
|
assert(context);
|
||||||
|
|
||||||
|
GLuint shader = glCreateShader(type);
|
||||||
|
if (shader == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *bytes = g_resources_lookup_data(resource, 0, NULL);
|
||||||
|
if (!bytes) {
|
||||||
|
printf("Failed to load shader resource %s\n", resource);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build #define for OpenGL context information
|
||||||
|
gboolean is_es = gdk_gl_context_get_use_es(context);
|
||||||
|
int major, minor;
|
||||||
|
gdk_gl_context_get_version(context, &major, &minor);
|
||||||
|
char context_info_buf[128];
|
||||||
|
snprintf(context_info_buf, 128, "#define %s\n#define GL_%d\n#define GL_%d_%d\n", is_es ? "GL_ES" : "GL_NO_ES", major, major, minor);
|
||||||
|
|
||||||
|
gsize glib_size = 0;
|
||||||
|
const GLchar *source = g_bytes_get_data(bytes, &glib_size);
|
||||||
|
if (glib_size == 0 || glib_size > INT_MAX) {
|
||||||
|
printf("Invalid size for resource\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLchar **sources = malloc((num_extra + 1) * sizeof(GLchar *));
|
||||||
|
GLint *sizes = malloc((num_extra + 1) * sizeof(GLint));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_extra; ++i) {
|
||||||
|
sources[i] = extra_sources[i];
|
||||||
|
sizes[i] = -1;
|
||||||
|
}
|
||||||
|
sources[num_extra] = source;
|
||||||
|
sizes[num_extra] = glib_size;
|
||||||
|
|
||||||
|
glShaderSource(shader, num_extra + 1, sources, sizes);
|
||||||
|
glCompileShader(shader);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
free(sources);
|
||||||
|
free(sizes);
|
||||||
|
|
||||||
|
g_bytes_unref(bytes);
|
||||||
|
|
||||||
|
// Check compile status
|
||||||
|
GLint success;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||||
|
if (success == GL_FALSE) {
|
||||||
|
printf("Shader compilation failed for %s\n", resource);
|
||||||
|
|
||||||
|
glDeleteShader(shader);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint log_length;
|
||||||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if (log_length > 0) {
|
||||||
|
char *log = malloc(sizeof(char) * log_length);
|
||||||
|
glGetShaderInfoLog(shader, log_length - 1, &log_length, log);
|
||||||
|
|
||||||
|
printf("Shader %s log: %s\n", resource, log);
|
||||||
|
free(log);
|
||||||
|
|
||||||
|
glDeleteShader(shader);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint
|
||||||
|
gl_util_link_program(GLuint *shaders, size_t num_shaders)
|
||||||
|
{
|
||||||
|
GLuint program = glCreateProgram();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_shaders; ++i) {
|
||||||
|
glAttachShader(program, shaders[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
glLinkProgram(program);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
GLint success;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||||||
|
if (success == GL_FALSE) {
|
||||||
|
printf("Program linking failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint log_length;
|
||||||
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if (log_length > 0) {
|
||||||
|
char *log = malloc(sizeof(char) * log_length);
|
||||||
|
glGetProgramInfoLog(program, log_length - 1, &log_length, log);
|
||||||
|
|
||||||
|
printf("Program log: %s\n", log);
|
||||||
|
free(log);
|
||||||
|
}
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GLfloat quad_data[] = {
|
||||||
|
// Vertices
|
||||||
|
-1, -1,
|
||||||
|
1, -1,
|
||||||
|
-1, 1,
|
||||||
|
1, 1,
|
||||||
|
// Texcoords
|
||||||
|
0, 0,
|
||||||
|
1, 0,
|
||||||
|
0, 1,
|
||||||
|
1, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
GLuint gl_util_new_quad()
|
||||||
|
{
|
||||||
|
GdkGLContext *context = gdk_gl_context_get_current();
|
||||||
|
assert(context);
|
||||||
|
|
||||||
|
if (gdk_gl_context_get_use_es(context)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
GLuint buffer;
|
||||||
|
glGenBuffers(1, &buffer);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl_util_bind_quad(GLuint buffer)
|
||||||
|
{
|
||||||
|
GdkGLContext *context = gdk_gl_context_get_current();
|
||||||
|
assert(context);
|
||||||
|
|
||||||
|
if (gdk_gl_context_get_use_es(context)) {
|
||||||
|
glVertexAttribPointer(GL_UTIL_VERTEX_ATTRIBUTE, 2, GL_FLOAT, 0, 0, quad_data);
|
||||||
|
check_gl();
|
||||||
|
glEnableVertexAttribArray(GL_UTIL_VERTEX_ATTRIBUTE);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
glVertexAttribPointer(GL_UTIL_TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, 0, 0, quad_data + 8);
|
||||||
|
check_gl();
|
||||||
|
glEnableVertexAttribArray(GL_UTIL_TEX_COORD_ATTRIBUTE);
|
||||||
|
check_gl();
|
||||||
|
} else {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
glVertexAttribPointer(GL_UTIL_VERTEX_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
glEnableVertexAttribArray(GL_UTIL_VERTEX_ATTRIBUTE);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
glVertexAttribPointer(GL_UTIL_TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0, (void*) (8 * sizeof(float)));
|
||||||
|
glEnableVertexAttribArray(GL_UTIL_TEX_COORD_ATTRIBUTE);
|
||||||
|
check_gl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl_util_draw_quad(GLuint buffer)
|
||||||
|
{
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
check_gl();
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <epoxy/gl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define GL_UTIL_VERTEX_ATTRIBUTE 0
|
||||||
|
#define GL_UTIL_TEX_COORD_ATTRIBUTE 1
|
||||||
|
|
||||||
|
#define check_gl() gl_util_check_error(__FILE__, __LINE__)
|
||||||
|
void gl_util_check_error(const char *file, int line);
|
||||||
|
|
||||||
|
GLuint gl_util_load_shader(const char *resource, GLenum type, const char **extra_sources, size_t num_extra);
|
||||||
|
GLuint gl_util_link_program(GLuint *shaders, size_t num_shaders);
|
||||||
|
|
||||||
|
GLuint gl_util_new_quad();
|
||||||
|
void gl_util_bind_quad(GLuint buffer);
|
||||||
|
void gl_util_draw_quad(GLuint buffer);
|
|
@ -0,0 +1,141 @@
|
||||||
|
#include "gles2_debayer.h"
|
||||||
|
|
||||||
|
#include "camera.h"
|
||||||
|
#include "gl_util.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define VERTEX_ATTRIBUTE 0
|
||||||
|
#define TEX_COORD_ATTRIBUTE 1
|
||||||
|
|
||||||
|
struct _GLES2Debayer {
|
||||||
|
GLuint frame_buffer;
|
||||||
|
GLuint program;
|
||||||
|
GLuint uniform_transform;
|
||||||
|
GLuint uniform_pixel_size;
|
||||||
|
GLuint uniform_texture;
|
||||||
|
GLuint uniform_color_matrix;
|
||||||
|
|
||||||
|
GLuint quad;
|
||||||
|
};
|
||||||
|
|
||||||
|
GLES2Debayer *
|
||||||
|
gles2_debayer_new(MPPixelFormat format)
|
||||||
|
{
|
||||||
|
if (format != MP_PIXEL_FMT_BGGR8) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint frame_buffer;
|
||||||
|
glGenFramebuffers(1, &frame_buffer);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
GLuint shaders[] = {
|
||||||
|
gl_util_load_shader("/org/postmarketos/Megapixels/debayer.vert", GL_VERTEX_SHADER, NULL, 0),
|
||||||
|
gl_util_load_shader("/org/postmarketos/Megapixels/debayer.frag", GL_FRAGMENT_SHADER, NULL, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
GLuint program = gl_util_link_program(shaders, 2);
|
||||||
|
glBindAttribLocation(program, VERTEX_ATTRIBUTE, "vert");
|
||||||
|
glBindAttribLocation(program, TEX_COORD_ATTRIBUTE, "tex_coord");
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
GLES2Debayer *self = malloc(sizeof(GLES2Debayer));
|
||||||
|
self->frame_buffer = frame_buffer;
|
||||||
|
self->program = program;
|
||||||
|
|
||||||
|
self->uniform_transform = glGetUniformLocation(self->program, "transform");
|
||||||
|
self->uniform_pixel_size = glGetUniformLocation(self->program, "pixel_size");
|
||||||
|
self->uniform_texture = glGetUniformLocation(self->program, "texture");
|
||||||
|
self->uniform_color_matrix = glGetUniformLocation(self->program, "color_matrix");
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
self->quad = gl_util_new_quad();
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gles2_debayer_free(GLES2Debayer *self)
|
||||||
|
{
|
||||||
|
glDeleteFramebuffers(1, &self->frame_buffer);
|
||||||
|
|
||||||
|
glDeleteProgram(self->program);
|
||||||
|
|
||||||
|
free(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gles2_debayer_use(GLES2Debayer *self)
|
||||||
|
{
|
||||||
|
glUseProgram(self->program);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
gl_util_bind_quad(self->quad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gles2_debayer_configure(GLES2Debayer *self,
|
||||||
|
const uint32_t dst_width, const uint32_t dst_height,
|
||||||
|
const uint32_t src_width, const uint32_t src_height,
|
||||||
|
const uint32_t rotation,
|
||||||
|
const bool mirrored,
|
||||||
|
const float *colormatrix,
|
||||||
|
const uint8_t blacklevel)
|
||||||
|
{
|
||||||
|
glViewport(0, 0, dst_width, dst_height);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
GLfloat rotation_list[4] = { 0, -1, 0, 1 };
|
||||||
|
int rotation_index = 4 - rotation / 90;
|
||||||
|
|
||||||
|
GLfloat sin_rot = rotation_list[rotation_index];
|
||||||
|
GLfloat cos_rot = rotation_list[(rotation_index + 1) % 4];
|
||||||
|
GLfloat scale_x = mirrored ? 1 : -1;
|
||||||
|
GLfloat matrix[9] = {
|
||||||
|
cos_rot * scale_x, sin_rot, 0,
|
||||||
|
-sin_rot * scale_x, cos_rot, 0,
|
||||||
|
0, 0, 1,
|
||||||
|
};
|
||||||
|
glUniformMatrix3fv(self->uniform_transform, 1, GL_FALSE, matrix);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
GLfloat pixel_size_x = 1.0f / src_width;
|
||||||
|
GLfloat pixel_size_y = 1.0f / src_height;
|
||||||
|
glUniform2f(self->uniform_pixel_size, pixel_size_x, pixel_size_y);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
if (colormatrix) {
|
||||||
|
GLfloat transposed[9];
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
for (int j = 0; j < 3; ++j)
|
||||||
|
transposed[i + j * 3] = colormatrix[j + i * 3];
|
||||||
|
|
||||||
|
glUniformMatrix3fv(self->uniform_color_matrix, 1, GL_FALSE, transposed);
|
||||||
|
} else {
|
||||||
|
static const GLfloat identity[9] = {
|
||||||
|
1, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 0, 1,
|
||||||
|
};
|
||||||
|
glUniformMatrix3fv(self->uniform_color_matrix, 1, GL_FALSE, identity);
|
||||||
|
}
|
||||||
|
check_gl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gles2_debayer_process(GLES2Debayer *self, GLuint dst_id, GLuint source_id)
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self->frame_buffer);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, dst_id);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_id, 0);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, source_id);
|
||||||
|
glUniform1i(self->uniform_texture, 0);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
gl_util_draw_quad(self->quad);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include "camera.h"
|
||||||
|
#include "gl_util.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef struct _GLES2Debayer GLES2Debayer;
|
||||||
|
|
||||||
|
GLES2Debayer* gles2_debayer_new(MPPixelFormat format);
|
||||||
|
void gles2_debayer_free(GLES2Debayer *self);
|
||||||
|
|
||||||
|
void gles2_debayer_use(GLES2Debayer *self);
|
||||||
|
|
||||||
|
void gles2_debayer_configure(GLES2Debayer *self,
|
||||||
|
const uint32_t dst_width, const uint32_t dst_height,
|
||||||
|
const uint32_t src_width, const uint32_t src_height,
|
||||||
|
const uint32_t rotation,
|
||||||
|
const bool mirrored,
|
||||||
|
const float *colormatrix,
|
||||||
|
const uint8_t blacklevel);
|
||||||
|
|
||||||
|
void gles2_debayer_process(GLES2Debayer *self, GLuint dst_id, GLuint source_id);
|
|
@ -18,9 +18,8 @@
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <zbar.h>
|
#include <zbar.h>
|
||||||
#include "gl_utils.h"
|
#include "gl_util.h"
|
||||||
#include "camera_config.h"
|
#include "camera_config.h"
|
||||||
#include "quickpreview.h"
|
|
||||||
#include "io_pipeline.h"
|
#include "io_pipeline.h"
|
||||||
#include "process_pipeline.h"
|
#include "process_pipeline.h"
|
||||||
|
|
||||||
|
@ -330,6 +329,7 @@ draw_controls()
|
||||||
|
|
||||||
static GLuint blit_program;
|
static GLuint blit_program;
|
||||||
static GLuint blit_uniform_texture;
|
static GLuint blit_uniform_texture;
|
||||||
|
static GLuint quad;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
preview_realize(GtkGLArea *area)
|
preview_realize(GtkGLArea *area)
|
||||||
|
@ -340,17 +340,27 @@ preview_realize(GtkGLArea *area)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a VAO for OpenGL
|
||||||
|
if (!gtk_gl_area_get_use_es(area)) {
|
||||||
|
GLuint vao;
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
check_gl();
|
||||||
|
}
|
||||||
|
|
||||||
GLuint blit_shaders[] = {
|
GLuint blit_shaders[] = {
|
||||||
gl_load_shader("data/blit.vert", GL_VERTEX_SHADER),
|
gl_util_load_shader("/org/postmarketos/Megapixels/blit.vert", GL_VERTEX_SHADER, NULL, 0),
|
||||||
gl_load_shader("data/blit.frag", GL_FRAGMENT_SHADER),
|
gl_util_load_shader("/org/postmarketos/Megapixels/blit.frag", GL_FRAGMENT_SHADER, NULL, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
blit_program = gl_link_program(blit_shaders, 2);
|
blit_program = gl_util_link_program(blit_shaders, 2);
|
||||||
glBindAttribLocation(blit_program, 0, "vert");
|
glBindAttribLocation(blit_program, GL_UTIL_VERTEX_ATTRIBUTE, "vert");
|
||||||
glBindAttribLocation(blit_program, 1, "tex_coord");
|
glBindAttribLocation(blit_program, GL_UTIL_TEX_COORD_ATTRIBUTE, "tex_coord");
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
blit_uniform_texture = glGetUniformLocation(blit_program, "texture");
|
blit_uniform_texture = glGetUniformLocation(blit_program, "texture");
|
||||||
|
|
||||||
|
quad = gl_util_new_quad();
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -364,9 +374,9 @@ preview_draw(GtkGLArea *area, GdkGLContext *ctx, gpointer data)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #ifdef RENDERDOC
|
#ifdef RENDERDOC
|
||||||
// if (rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL);
|
if (rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL);
|
||||||
// #endif
|
#endif
|
||||||
|
|
||||||
glClearColor(0, 0, 0, 1);
|
glClearColor(0, 0, 0, 1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
@ -377,13 +387,10 @@ preview_draw(GtkGLArea *area, GdkGLContext *ctx, gpointer data)
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, mp_process_pipeline_buffer_get_texture_id(current_preview_buffer));
|
glBindTexture(GL_TEXTURE_2D, mp_process_pipeline_buffer_get_texture_id(current_preview_buffer));
|
||||||
glUniform1i(blit_uniform_texture, 0);
|
glUniform1i(blit_uniform_texture, 0);
|
||||||
|
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, gl_quad_vertices);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, gl_quad_texcoords);
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
|
gl_util_bind_quad(quad);
|
||||||
|
gl_util_draw_quad(quad);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -433,9 +440,9 @@ preview_draw(GtkGLArea *area, GdkGLContext *ctx, gpointer data)
|
||||||
|
|
||||||
glFlush();
|
glFlush();
|
||||||
|
|
||||||
// #ifdef RENDERDOC
|
#ifdef RENDERDOC
|
||||||
// if(rdoc_api) rdoc_api->EndFrameCapture(NULL, NULL);
|
if(rdoc_api) rdoc_api->EndFrameCapture(NULL, NULL);
|
||||||
// #endif
|
#endif
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -758,6 +765,9 @@ on_realize(GtkWidget *window, gpointer *data)
|
||||||
{
|
{
|
||||||
GtkNative *native = gtk_widget_get_native(window);
|
GtkNative *native = gtk_widget_get_native(window);
|
||||||
mp_process_pipeline_init_gl(gtk_native_get_surface(native));
|
mp_process_pipeline_init_gl(gtk_native_get_surface(native));
|
||||||
|
|
||||||
|
camera = mp_get_camera_config(0);
|
||||||
|
update_io_pipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -778,13 +788,10 @@ startup(GApplication *app)
|
||||||
g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme",
|
g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme",
|
||||||
TRUE, NULL);
|
TRUE, NULL);
|
||||||
|
|
||||||
GtkBuilder *builder;
|
assert(g_resources_lookup_data("/org/postmarketos/Megapixels/camera.ui", 0, NULL) != NULL);
|
||||||
if (access("camera.ui", F_OK) != -1) {
|
|
||||||
builder = gtk_builder_new_from_file("camera.ui");
|
GtkBuilder *builder = gtk_builder_new_from_resource(
|
||||||
} else {
|
|
||||||
builder = gtk_builder_new_from_file(
|
|
||||||
"/org/postmarketos/Megapixels/camera.ui");
|
"/org/postmarketos/Megapixels/camera.ui");
|
||||||
}
|
|
||||||
|
|
||||||
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
|
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
|
||||||
GtkWidget *shutter = GTK_WIDGET(gtk_builder_get_object(builder, "shutter"));
|
GtkWidget *shutter = GTK_WIDGET(gtk_builder_get_object(builder, "shutter"));
|
||||||
|
@ -842,12 +849,8 @@ startup(GApplication *app)
|
||||||
G_CALLBACK(on_control_slider_changed), NULL);
|
G_CALLBACK(on_control_slider_changed), NULL);
|
||||||
|
|
||||||
GtkCssProvider *provider = gtk_css_provider_new();
|
GtkCssProvider *provider = gtk_css_provider_new();
|
||||||
if (access("camera.css", F_OK) != -1) {
|
|
||||||
gtk_css_provider_load_from_path(provider, "camera.css");
|
|
||||||
} else {
|
|
||||||
gtk_css_provider_load_from_resource(
|
gtk_css_provider_load_from_resource(
|
||||||
provider, "/org/postmarketos/Megapixels/camera.css");
|
provider, "/org/postmarketos/Megapixels/camera.css");
|
||||||
}
|
|
||||||
GtkStyleContext *context = gtk_widget_get_style_context(error_box);
|
GtkStyleContext *context = gtk_widget_get_style_context(error_box);
|
||||||
gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
|
gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
|
||||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
@ -868,9 +871,6 @@ startup(GApplication *app)
|
||||||
|
|
||||||
mp_io_pipeline_start();
|
mp_io_pipeline_start();
|
||||||
|
|
||||||
camera = mp_get_camera_config(0);
|
|
||||||
update_io_pipeline();
|
|
||||||
|
|
||||||
gtk_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(window));
|
gtk_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(window));
|
||||||
gtk_widget_show(window);
|
gtk_widget_show(window);
|
||||||
}
|
}
|
|
@ -5,18 +5,14 @@
|
||||||
#include "io_pipeline.h"
|
#include "io_pipeline.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "quickpreview.h"
|
#include "gles2_debayer.h"
|
||||||
#include "gl_quickpreview.h"
|
|
||||||
#include <tiffio.h>
|
#include <tiffio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#include "gl_utils.h"
|
#include "gl_util.h"
|
||||||
#include <EGL/egl.h>
|
|
||||||
#include <EGL/eglext.h>
|
|
||||||
// #include <gdk/gdkwayland.h>
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <drm/drm_fourcc.h>
|
#include <drm/drm_fourcc.h>
|
||||||
|
|
||||||
|
@ -82,9 +78,9 @@ find_processor(char *script)
|
||||||
wordfree(&exp_result);
|
wordfree(&exp_result);
|
||||||
|
|
||||||
// Check postprocess.h in the current working directory
|
// Check postprocess.h in the current working directory
|
||||||
sprintf(script, "%s", filename);
|
sprintf(script, "data/%s", filename);
|
||||||
if (access(script, F_OK) != -1) {
|
if (access(script, F_OK) != -1) {
|
||||||
sprintf(script, "./%s", filename);
|
sprintf(script, "./data/%s", filename);
|
||||||
printf("Found postprocessor script at %s\n", script);
|
printf("Found postprocessor script at %s\n", script);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -158,9 +154,6 @@ struct _MPProcessPipelineBuffer {
|
||||||
};
|
};
|
||||||
static MPProcessPipelineBuffer output_buffers[NUM_BUFFERS];
|
static MPProcessPipelineBuffer output_buffers[NUM_BUFFERS];
|
||||||
|
|
||||||
static int output_buffer_width = 0;
|
|
||||||
static int output_buffer_height = 0;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
mp_process_pipeline_buffer_ref(MPProcessPipelineBuffer *buf)
|
mp_process_pipeline_buffer_ref(MPProcessPipelineBuffer *buf)
|
||||||
{
|
{
|
||||||
|
@ -179,37 +172,10 @@ mp_process_pipeline_buffer_get_texture_id(MPProcessPipelineBuffer *buf)
|
||||||
return buf->texture_id;
|
return buf->texture_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GLQuickPreview *gl_quick_preview_state = NULL;
|
static GLES2Debayer *gles2_debayer = NULL;
|
||||||
|
|
||||||
static GdkGLContext *context;
|
static GdkGLContext *context;
|
||||||
|
|
||||||
static PFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;
|
|
||||||
static PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC eglExportDMABUFImageQueryMESA;
|
|
||||||
|
|
||||||
// static const char *
|
|
||||||
// egl_get_error_str()
|
|
||||||
// {
|
|
||||||
// EGLint error = eglGetError();
|
|
||||||
// switch (error) {
|
|
||||||
// case EGL_SUCCESS: return "EGL_SUCCESS";
|
|
||||||
// case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
|
|
||||||
// case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
|
|
||||||
// case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
|
|
||||||
// case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
|
|
||||||
// case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
|
|
||||||
// case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
|
|
||||||
// case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
|
|
||||||
// case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
|
|
||||||
// case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
|
|
||||||
// case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
|
|
||||||
// case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
|
|
||||||
// case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
|
|
||||||
// case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
|
|
||||||
// case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
|
|
||||||
// }
|
|
||||||
// return "Unknown";
|
|
||||||
// }
|
|
||||||
|
|
||||||
#define RENDERDOC
|
#define RENDERDOC
|
||||||
|
|
||||||
#ifdef RENDERDOC
|
#ifdef RENDERDOC
|
||||||
|
@ -230,6 +196,7 @@ init_gl(MPPipeline *pipeline, GdkSurface **surface)
|
||||||
|
|
||||||
gdk_gl_context_set_use_es(context, true);
|
gdk_gl_context_set_use_es(context, true);
|
||||||
gdk_gl_context_set_required_version(context, 2, 0);
|
gdk_gl_context_set_required_version(context, 2, 0);
|
||||||
|
gdk_gl_context_set_forward_compatible(context, false);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
gdk_gl_context_set_debug_enabled(context, true);
|
gdk_gl_context_set_debug_enabled(context, true);
|
||||||
#else
|
#else
|
||||||
|
@ -247,28 +214,21 @@ init_gl(MPPipeline *pipeline, GdkSurface **surface)
|
||||||
gdk_gl_context_make_current(context);
|
gdk_gl_context_make_current(context);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
eglExportDMABUFImageMESA = (PFNEGLEXPORTDMABUFIMAGEMESAPROC)
|
// Make a VAO for OpenGL
|
||||||
eglGetProcAddress("eglExportDMABUFImageMESA");
|
if (!gdk_gl_context_get_use_es(context)) {
|
||||||
eglExportDMABUFImageQueryMESA = (PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC)
|
GLuint vao;
|
||||||
eglGetProcAddress("eglExportDMABUFImageQueryMESA");
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
// Generate textures for the buffers
|
|
||||||
// GLuint textures[NUM_BUFFERS * 2];
|
|
||||||
// glGenTextures(NUM_BUFFERS * 2, textures);
|
|
||||||
|
|
||||||
// for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
|
||||||
// input_buffers[i].texture_id = textures[i];
|
|
||||||
// input_buffers[i].egl_image = EGL_NO_IMAGE;
|
|
||||||
// input_buffers[i].dma_fd = -1;
|
|
||||||
// }
|
|
||||||
// for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
|
||||||
// output_buffers[i].texture_id = textures[NUM_BUFFERS + i];
|
|
||||||
// output_buffers[i].egl_image = EGL_NO_IMAGE;
|
|
||||||
// output_buffers[i].dma_fd = -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
gl_quick_preview_state = gl_quick_preview_new();
|
|
||||||
check_gl();
|
check_gl();
|
||||||
|
}
|
||||||
|
|
||||||
|
gles2_debayer = gles2_debayer_new(MP_PIXEL_FMT_BGGR8);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
gles2_debayer_use(gles2_debayer);
|
||||||
|
|
||||||
for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
||||||
glGenTextures(1, &output_buffers[i].texture_id);
|
glGenTextures(1, &output_buffers[i].texture_id);
|
||||||
|
@ -279,7 +239,11 @@ init_gl(MPPipeline *pipeline, GdkSurface **surface)
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
printf("Initialized OpenGL\n");
|
gboolean is_es = gdk_gl_context_get_use_es(context);
|
||||||
|
int major, minor;
|
||||||
|
gdk_gl_context_get_version(context, &major, &minor);
|
||||||
|
|
||||||
|
printf("Initialized %s %d.%d\n", is_es ? "OpenGL ES" : "OpenGL", major, minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -293,8 +257,6 @@ process_image_for_preview(const uint8_t *image)
|
||||||
{
|
{
|
||||||
clock_t t1 = clock();
|
clock_t t1 = clock();
|
||||||
|
|
||||||
assert(gl_quick_preview_state && ql_quick_preview_supports_format(gl_quick_preview_state, mode.pixel_format));
|
|
||||||
|
|
||||||
// Pick an available buffer
|
// Pick an available buffer
|
||||||
MPProcessPipelineBuffer *output_buffer = NULL;
|
MPProcessPipelineBuffer *output_buffer = NULL;
|
||||||
for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
||||||
|
@ -311,8 +273,6 @@ process_image_for_preview(const uint8_t *image)
|
||||||
#ifdef RENDERDOC
|
#ifdef RENDERDOC
|
||||||
if (rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL);
|
if (rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL);
|
||||||
#endif
|
#endif
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
// Copy image to a GL texture. TODO: This can be avoided
|
// Copy image to a GL texture. TODO: This can be avoided
|
||||||
GLuint input_texture;
|
GLuint input_texture;
|
||||||
|
@ -325,24 +285,13 @@ process_image_for_preview(const uint8_t *image)
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mode.width, mode.height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mode.width, mode.height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
|
gles2_debayer_process(
|
||||||
gl_quick_preview(
|
gles2_debayer, output_buffer->texture_id, input_texture);
|
||||||
gl_quick_preview_state,
|
|
||||||
output_buffer->texture_id, output_buffer_width, output_buffer_height,
|
|
||||||
input_texture, mode.width, mode.height,
|
|
||||||
mode.pixel_format,
|
|
||||||
camera->rotate, camera->mirrored,
|
|
||||||
camera->previewmatrix[0] == 0 ? NULL : camera->previewmatrix,
|
|
||||||
camera->blacklevel);
|
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
// surface = cairo_image_surface_create(
|
|
||||||
// CAIRO_FORMAT_RGB24, preview_width, preview_height);
|
|
||||||
// uint32_t *pixels = (uint32_t *)cairo_image_surface_get_data(surface);
|
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glDeleteTextures(1, &input_texture);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
|
|
||||||
clock_t t2 = clock();
|
clock_t t2 = clock();
|
||||||
printf("%fms\n", (float)(t2 - t1) / CLOCKS_PER_SEC * 1000);
|
printf("%fms\n", (float)(t2 - t1) / CLOCKS_PER_SEC * 1000);
|
||||||
|
@ -727,10 +676,10 @@ mp_process_pipeline_capture()
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_output_buffers()
|
on_output_changed()
|
||||||
{
|
{
|
||||||
output_buffer_width = mode.width / 2;
|
int output_buffer_width = mode.width / 2;
|
||||||
output_buffer_height = mode.height / 2;
|
int output_buffer_height = mode.height / 2;
|
||||||
|
|
||||||
if (camera->rotate != 0 || camera->rotate != 180) {
|
if (camera->rotate != 0 || camera->rotate != 180) {
|
||||||
int tmp = output_buffer_width;
|
int tmp = output_buffer_width;
|
||||||
|
@ -744,12 +693,20 @@ update_output_buffers()
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
gles2_debayer_configure(
|
||||||
|
gles2_debayer,
|
||||||
|
output_buffer_width, output_buffer_height,
|
||||||
|
mode.width, mode.height,
|
||||||
|
camera->rotate, camera->mirrored,
|
||||||
|
camera->previewmatrix[0] == 0 ? NULL : camera->previewmatrix,
|
||||||
|
camera->blacklevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state)
|
update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state)
|
||||||
{
|
{
|
||||||
const bool buffer_update_required = (!mp_camera_mode_is_equivalent(&mode, &state->mode) || preview_width != state->preview_width || preview_height != state->preview_height);
|
const bool output_changed = (!mp_camera_mode_is_equivalent(&mode, &state->mode) || preview_width != state->preview_width || preview_height != state->preview_height);
|
||||||
|
|
||||||
camera = state->camera;
|
camera = state->camera;
|
||||||
mode = state->mode;
|
mode = state->mode;
|
||||||
|
@ -766,8 +723,8 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state
|
||||||
exposure_is_manual = state->exposure_is_manual;
|
exposure_is_manual = state->exposure_is_manual;
|
||||||
exposure = state->exposure;
|
exposure = state->exposure;
|
||||||
|
|
||||||
if (buffer_update_required) {
|
if (output_changed) {
|
||||||
update_output_buffers();
|
on_output_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mp_main_state main_state = {
|
struct mp_main_state main_state = {
|
|
@ -1,120 +0,0 @@
|
||||||
#include "quickpreview.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
static void
|
|
||||||
test_quick_preview_fuzz()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < 10000; ++i) {
|
|
||||||
uint32_t width = rand() % 127 + 1;
|
|
||||||
uint32_t height = rand() % 127 + 1;
|
|
||||||
uint32_t format = rand() % (MP_PIXEL_FMT_MAX - 1) + 1;
|
|
||||||
|
|
||||||
assert(width > 0 && height > 0);
|
|
||||||
|
|
||||||
switch (format) {
|
|
||||||
case MP_PIXEL_FMT_BGGR8:
|
|
||||||
case MP_PIXEL_FMT_GBRG8:
|
|
||||||
case MP_PIXEL_FMT_GRBG8:
|
|
||||||
case MP_PIXEL_FMT_RGGB8:
|
|
||||||
width += width % 2;
|
|
||||||
height += height % 2;
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_BGGR10P:
|
|
||||||
case MP_PIXEL_FMT_GBRG10P:
|
|
||||||
case MP_PIXEL_FMT_GRBG10P:
|
|
||||||
case MP_PIXEL_FMT_RGGB10P:
|
|
||||||
width += width % 2;
|
|
||||||
height += height % 2;
|
|
||||||
break;
|
|
||||||
case MP_PIXEL_FMT_UYVY:
|
|
||||||
case MP_PIXEL_FMT_YUYV:
|
|
||||||
width += width % 4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rotation;
|
|
||||||
switch (rand() % 3) {
|
|
||||||
case 0:
|
|
||||||
rotation = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rotation = 90;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
rotation = 180;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rotation = 270;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mirrored = rand() % 2;
|
|
||||||
|
|
||||||
float matbuf[9];
|
|
||||||
float *colormatrix = NULL;
|
|
||||||
if (rand() % 2) {
|
|
||||||
for (int j = 0; j < 9; ++j) {
|
|
||||||
matbuf[j] = (double)rand() / RAND_MAX * 2.0;
|
|
||||||
}
|
|
||||||
colormatrix = matbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t blacklevel = rand() % 3;
|
|
||||||
|
|
||||||
size_t src_size = mp_pixel_format_width_to_bytes(format, width) * height;
|
|
||||||
uint8_t *src = malloc(src_size);
|
|
||||||
for (int j = 0; j < src_size; ++j) {
|
|
||||||
src[j] = rand();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t preview_width = mp_pixel_format_width_to_colors(format, width);
|
|
||||||
uint32_t preview_height = mp_pixel_format_height_to_colors(format, height);
|
|
||||||
if (preview_width > 32 && preview_height > 32) {
|
|
||||||
preview_width /= (1 + rand() % 2);
|
|
||||||
preview_height /= (1 + rand() % 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t dst_width, dst_height, skip;
|
|
||||||
quick_preview_size(
|
|
||||||
&dst_width,
|
|
||||||
&dst_height,
|
|
||||||
&skip,
|
|
||||||
preview_width,
|
|
||||||
preview_height,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
format,
|
|
||||||
rotation);
|
|
||||||
|
|
||||||
uint32_t *dst = malloc(dst_width * dst_height * sizeof(uint32_t));
|
|
||||||
|
|
||||||
quick_preview(
|
|
||||||
dst,
|
|
||||||
dst_width,
|
|
||||||
dst_height,
|
|
||||||
src,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
format,
|
|
||||||
rotation,
|
|
||||||
mirrored,
|
|
||||||
colormatrix,
|
|
||||||
blacklevel,
|
|
||||||
skip);
|
|
||||||
|
|
||||||
free(dst);
|
|
||||||
free(src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
|
||||||
g_test_add_func("/quick_preview/fuzz", test_quick_preview_fuzz);
|
|
||||||
return g_test_run();
|
|
||||||
}
|
|